From 80ad6e168be8399934f51f341b82e7193f91d84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20L=C3=B3pez=20L=C3=B3pez?= Date: Tue, 7 Jul 2026 17:44:53 +0200 Subject: [PATCH] feat: ignore test_and_release in PRs without code changes --- .circleci/config.yml | 2072 +---------------- .circleci/continue_config.yml | 2054 ++++++++++++++++ .circleci/continue_config_light.yml | 14 + CONTRIBUTING.md | 32 + cliv2/internal/persona/agent/agent.go | 6 +- .../persona/interactive/interactive_test.go | 12 +- scripts/ci/code-change-pathspecs.txt | 16 + scripts/ci/continue-pipeline.sh | 34 + scripts/ci/has-code-changes.sh | 32 + scripts/ci/is-docs-only-changes.sh | 24 + scripts/ci/list-changed-files.sh | 13 + scripts/ci/test_has_code_changes.sh | 77 + scripts/ci/test_is_docs_only_changes.sh | 58 + 13 files changed, 2383 insertions(+), 2061 deletions(-) create mode 100644 .circleci/continue_config.yml create mode 100644 .circleci/continue_config_light.yml create mode 100644 scripts/ci/code-change-pathspecs.txt create mode 100755 scripts/ci/continue-pipeline.sh create mode 100755 scripts/ci/has-code-changes.sh create mode 100755 scripts/ci/is-docs-only-changes.sh create mode 100755 scripts/ci/list-changed-files.sh create mode 100755 scripts/ci/test_has_code_changes.sh create mode 100755 scripts/ci/test_is_docs_only_changes.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 8d4a74bc31..5278f2bf26 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,2067 +1,31 @@ version: 2.1 -parameters: - cli_download_base_url: - type: string - default: 'https://downloads.snyk.io/' - fips_cli_download_base_url: - type: string - default: 'https://downloads.snyk.io/fips/' - experimental_cli_download_base_url: - type: string - default: 'https://downloads.snyk.io/experimental/' - go_download_base_url: - type: string - default: 'https://dl.google.com/go/' - fips_go_download_base_url: - type: string - default: 'https://aka.ms/golang/release/latest/' - go_version: - type: string - # https://go.dev/doc/devel/release - default: '1.26.4' - aws_version: - type: string - # https://github.com/aws/aws-cli/blob/v2/CHANGELOG.rst - default: '2.4.12' - gh_version: - type: string - # https://github.com/cli/cli/releases - default: '2.7.0' - windows_cache_dir: - type: string - default: 'C:\tools-cache' - windows_env_script: - type: string - default: 'snyk-env.ps1' - windows_bash_env_script: - type: string - default: 'snyk-env.sh' +setup: true orbs: - prodsec: snyk/prodsec-orb@1 - snyk: snyk/snyk@2.0.3 - aws-cli: circleci/aws-cli@2.0.3 - gh: circleci/github-cli@2.1.0 + continuation: circleci/continuation@1 -executors: - alpine: - docker: - - image: alpine:3.23 - resource_class: xlarge - alpine-arm64: - docker: - - image: alpine:3.23 - resource_class: arm.xlarge - generic-ubuntu: - docker: - - image: ubuntu:latest - resource_class: small - linux-machine-amd64: - machine: - image: ubuntu-2204:current - resource_class: medium - docker-amd64: - docker: - - image: snyklabs/cli-build-private:20260610-125138 - auth: - username: $DOCKER_CLI_BUILD_USERNAME - password: $DOCKER_CLI_BUILD_PASSWORD - # working_directory: /mnt/ramdisk/snyk - resource_class: large - docker-amd64-xl: - docker: - - image: snyklabs/cli-build-private:20260610-125138 - auth: - username: $DOCKER_CLI_BUILD_USERNAME - password: $DOCKER_CLI_BUILD_PASSWORD - # working_directory: /mnt/ramdisk/snyk - resource_class: xlarge - docker-arm64: - docker: - - image: snyklabs/cli-build-private-arm64:20260610-125138 - auth: - username: $DOCKER_CLI_BUILD_USERNAME - password: $DOCKER_CLI_BUILD_PASSWORD - # working_directory: /mnt/ramdisk/snyk - resource_class: arm.large - docker-arm64-xl: - docker: - - image: snyklabs/cli-build-private-arm64:20260610-125138 - auth: - username: $DOCKER_CLI_BUILD_USERNAME - password: $DOCKER_CLI_BUILD_PASSWORD - # working_directory: /mnt/ramdisk/snyk - resource_class: arm.xlarge - linux-ubuntu-jammy-amd64: - docker: - - image: ubuntu:jammy - # working_directory: /mnt/ramdisk/snyk - resource_class: medium - linux-ubuntu-focal-amd64: - docker: - - image: ubuntu:focal - # working_directory: /mnt/ramdisk/snyk - resource_class: medium - linux-ubuntu-latest-amd64: - docker: - - image: ubuntu:latest - # working_directory: /mnt/ramdisk/snyk - resource_class: medium - linux-ubuntu-bionic-beaver-amd64: - docker: - - image: ubuntu:18.04 - # working_directory: /mnt/ramdisk/snyk - resource_class: medium - linux-ubuntu-latest-arm64: - docker: - - image: ubuntu:latest - # working_directory: /mnt/ramdisk/snyk - resource_class: arm.medium - linux-ubuntu-jammy-arm64: - docker: - - image: ubuntu:jammy - # working_directory: /mnt/ramdisk/snyk - resource_class: arm.medium - linux-ubuntu-focal-arm64: - docker: - - image: ubuntu:focal - # working_directory: /mnt/ramdisk/snyk - resource_class: arm.medium - macos-arm64: - macos: - # https://circleci.com/developer/machine/image/xcode#image-tags - xcode: '26.1.0' - resource_class: m4pro.medium - macos-arm64-large: - macos: - # https://circleci.com/developer/machine/image/xcode#image-tags - xcode: '26.1.0' - resource_class: m4pro.large - win-server2022-amd64: - machine: - image: windows-server-2022-gui:2024.01.1 - resource_class: windows.large - shell: powershell - win-server2019-amd64: - machine: - image: windows-server-2019-vs2019:2022.08.1 - resource_class: windows.medium - shell: powershell - cbl-mariner: - docker: - - image: mcr.microsoft.com/cbl-mariner/base/python:3.9.14-8-cm2.0.20240301-arm64 - resource_class: arm.medium - suse-linux-fips: - docker: - - image: registry.suse.com/bci/bci-base-fips:15.6 - resource_class: arm.medium - -commands: - make-binary: - parameters: - go_arch: - type: string - go_target_os: - type: string - make_target: - type: string - default: 'build BUILD_MODE=private' - c_compiler: - type: string - default: '' - static: - type: boolean - default: false - steps: - - when: - condition: << parameters.static >> - steps: - - run: - name: Build static << parameters.go_target_os >>/<< parameters.go_arch >> - shell: bash - environment: - CC: << parameters.c_compiler >> - MACOSX_DEPLOYMENT_TARGET: 13.0 - command: | - # load Windows $Env:Path values of tools necessary to execute the build (like Go) - if [ -f "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>" ]; then source "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>"; fi - make << parameters.make_target >> GOOS=<< parameters.go_target_os >> GOARCH=<< parameters.go_arch >> STATIC_NODE_BINARY=true CGO_ENABLED=0 - - unless: - condition: << parameters.static >> - steps: - - run: - name: Build << parameters.go_target_os >>/<< parameters.go_arch >> - shell: bash - environment: - CC: << parameters.c_compiler >> - MACOSX_DEPLOYMENT_TARGET: 13.0 - command: | - # load Windows $Env:Path values of tools necessary to execute the build (like Go) - if [ -f "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>" ]; then source "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>"; fi - make << parameters.make_target >> GOOS=<< parameters.go_target_os >> GOARCH=<< parameters.go_arch >> STATIC_NODE_BINARY=false CGO_ENABLED=1 - install-go: - parameters: - go_os: - type: string - go_target_os: - type: string - go_arch: - type: string - base_url: - type: string - extraction_path: - type: string - cache_key_file: - type: string - default: go_cache_key.txt - steps: - - run: - name: Create Cache Key - command: | - echo << parameters.extraction_path >>-<< parameters.base_url >>-<< parameters.go_target_os >>-<< parameters.go_arch >>-<< pipeline.parameters.go_version >> > << parameters.cache_key_file >> - cat << parameters.cache_key_file >> - - restore_cache: - name: Restoring go binary cache - keys: - - go-binary-cache-{{ checksum "<< parameters.cache_key_file >>" }} - - run: - name: Download go binary - command: python ./scripts/download_go.py << pipeline.parameters.go_version >> --go_os=<< parameters.go_os >> --go_arch=<< parameters.go_arch >> --base_url=<< parameters.base_url >> --extraction_path=<< parameters.extraction_path >> - - save_cache: - name: Caching go binary - key: go-binary-cache-{{ checksum "<< parameters.cache_key_file >>" }} - paths: - - << parameters.extraction_path >>/go - - unless: - condition: - equal: ['windows', << parameters.go_os >>] - steps: - - run: - name: Add go binary to PATH - command: echo "export PATH=$(realpath << parameters.extraction_path >>/go/bin):\$PATH" >> "$BASH_ENV" - - when: - condition: - equal: ['windows', << parameters.go_os >>] - steps: - - run: - name: Add go binary to PATH (via snyk-env) - shell: powershell - command: | - $goBin = '<< parameters.extraction_path >>\go\bin' - $envScript = '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>' - $bashEnvScript = '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_bash_env_script >>' - - if (-not (Test-Path $envScript)) { - New-Item -Path $envScript -ItemType File -Force | Out-Null - } - '$Env:Path = "' + $goBin + ';" + $Env:Path' | Out-File -FilePath $envScript -Append -Encoding UTF8 - - if (-not (Test-Path $bashEnvScript)) { - New-Item -Path $bashEnvScript -ItemType File -Force | Out-Null - } - $bashPath = $goBin.Replace('\', '/').Replace('C:', '/c') - $bashLine = 'export PATH="' + $bashPath + ':$PATH"' - [System.IO.File]::AppendAllText($bashEnvScript, $bashLine + "`n", (New-Object System.Text.UTF8Encoding $false)) - - install-deps-windows-native-build: - steps: - - run: - name: Ensure tools cache directory - shell: powershell - command: | - $cacheDir = '<< pipeline.parameters.windows_cache_dir >>' - if (-not (Test-Path $cacheDir)) { - New-Item -ItemType Directory -Path $cacheDir | Out-Null - } - - restore_cache: - name: Restoring Windows tools cache - keys: - - windows-tools-cache-v5-{{ arch }}-{{ checksum ".nvmrc" }} - - run: - name: Install Node.js (native) - shell: powershell - command: | - .\scripts\windows\install-node.ps1 - - run: - name: Install Apache Maven 3.8.2 (native) - shell: powershell - command: | - .\scripts\windows\install-maven.ps1 - - run: - name: Install Gradle 8.1.1 (native) - shell: powershell - command: | - .\scripts\windows\install-gradle.ps1 - - run: - name: Install .NET SDK 8.0.100 (native) - shell: powershell - command: | - .\scripts\windows\install-dotnet-sdk.ps1 - - run: - name: Install Python 3.12.8 (native) - shell: powershell - command: | - .\scripts\windows\install-python3.ps1 - - run: - name: Install GNU Make 4.4.1 (native) - shell: powershell - command: | - .\scripts\windows\install-make.ps1 - - run: - name: Ensure Python and uv - shell: powershell - command: | - if (Test-Path '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>') { . '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>' } - .\scripts\windows\ensure-python-uv.ps1 - - save_cache: - name: Saving Windows tools cache - key: windows-tools-cache-v5-{{ arch }}-{{ checksum ".nvmrc" }} - paths: - - << pipeline.parameters.windows_cache_dir >> - - C:\ProgramData\nvm - - install-deps-windows-native-full-signing: - steps: - - install-deps-windows-signing - - install-deps-windows-native-build - - install-deps-windows-signing: - steps: - - run: - name: Generate Cache Key - command: | - date +%U%Y >> ~/cache_key.txt - cat ~/cache_key.txt - - restore_cache: - name: Restoring DigitCert cache - keys: - - digicert-cache-v3-{{ arch }}-{{ checksum "~/cache_key.txt" }} - - run: - name: Install DigiCert Keylocker Tools - shell: powershell - command: | - # Navigate to C: drive - Set-Location C:\ - - # Check if the file exists in the user's home directory - $filePath = Join-Path $env:USERPROFILE 'smtools-windows-x64.msi' - if (Test-Path $filePath) { - Write-Host "File exists. Moving to C:" - Copy-Item $filePath -Destination .\ - } - else { - Write-Host "No existing file found. Downloading..." - # Download the file using Invoke-WebRequest - curl.exe -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:$env:SM_API_KEY" -o smtools-windows-x64.msi - # Copy the downloaded file to the user's home directory - Copy-Item 'smtools-windows-x64.msi' -Destination $env:USERPROFILE - } - - # Execute the MSI installer - msiexec.exe /i smtools-windows-x64.msi /quiet /qn | Wait-Process - & 'C:\Program Files\DigiCert\DigiCert One Signing Manager Tools\smksp_cert_sync.exe' - - # Manual resync - & 'C:\Program Files\DigiCert\DigiCert One Signing Manager Tools\smctl.exe' windows certsync - - save_cache: - name: Saving DigitCert cache - key: digicert-cache-v3-{{ arch }}-{{ checksum "~/cache_key.txt" }} - paths: - - ~\smtools-windows-x64.msi - - install-deps-windows-full-signing: - steps: - - install-deps-windows-signing - - install-deps-noop: - steps: - - run: - name: No dependencies to install - command: echo all done! - - setup-go-private-modules: - description: >- - Configure git and Go to fetch private snyk modules using the - GITHUB_PRIVATE_TOKEN provided by the `go-private-modules` context. - Safe to call on Linux, macOS and Windows (uses bash on all executors). +jobs: + detect-code-changes: + executor: continuation/default steps: + - checkout: + fetch-depth: 0 - run: - name: Configure access to private Snyk Go modules - shell: bash + name: Select continuation config command: | - # Load Windows env (PATH for git/go) if running on the Windows executor. - if [ -f "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>" ]; then - source "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>" + git fetch origin main --depth=100 + if ./scripts/ci/has-code-changes.sh; then + echo '.circleci/continue_config.yml' > /tmp/continuation-config-path.txt + else + echo '.circleci/continue_config_light.yml' > /tmp/continuation-config-path.txt fi - if [ -z "${GITHUB_PRIVATE_TOKEN}" ]; then - echo "GITHUB_PRIVATE_TOKEN is not set; skipping private Snyk modules setup." - echo "Add the 'go-private-modules' context to this job if private modules are required." - exit 0 - fi - git config --global url."https://${GITHUB_PRIVATE_TOKEN}:x-oauth-basic@github.com/snyk".insteadOf "https://github.com/snyk" - # Propagate GOPRIVATE to subsequent bash steps. - echo 'export GOPRIVATE=github.com/snyk' >> "$BASH_ENV" - - install-deps-python: - parameters: - os: - type: string - default: linux - modules: - type: string - default: requests PyYAML - steps: - - when: - condition: - matches: - pattern: '^(linux.*|macos.*|alpine.*|docker.*)' - value: << parameters.os >> - steps: - - run: - name: Installing python modules - command: python3 -m pip install << parameters.modules >> - - when: - condition: - matches: - pattern: '^(win.*|cbl-mariner.*)' - value: << parameters.os >> - steps: - - run: - shell: bash.exe - name: Installing python modules - command: python -m pip install << parameters.modules >> - - install-deps-macos-full: - parameters: - items: - type: string - default: go gradle python pipenv elixir composer gradle@9 maven dotnet uv - steps: - - run: - name: Installing Rosetta - command: softwareupdate --install-rosetta --agree-to-license - - run: - name: Update Homebrew - command: brew update - - restore_cache: - key: acceptance-tests-macos-<< parameters.items >> - - run: - name: Installing sdks and tools via homebrew - command: | - HOMEBREW_NO_ASK=1 brew install << parameters.items >> - echo 'export PATH="/opt/homebrew/opt/gradle@9/bin:$PATH"' >> "$BASH_ENV" - - save_cache: - key: acceptance-tests-macos-<< parameters.items >> - paths: - - ~/Library/Caches/Homebrew - - install-deps-python: - os: macos - - run: - name: Upgrade npm to satisfy package.json engine requirements (>=11.10) - command: npm install -g npm@^11.10 - - restore_cache: - keys: - - acceptance-{{ checksum "scripts/install-sbt.sh" }} - - run: - name: Installing sbt 1.x - command: ./scripts/install-sbt.sh - - save_cache: - key: acceptance-{{ checksum "scripts/install-sbt.sh" }} - paths: - - ~/sbt - - install-deps-macos-build: - parameters: - items: - type: string - default: go gradle python elixir composer gradle@9 maven sbt dotnet - steps: - - run: - name: Installing Rosetta - command: softwareupdate --install-rosetta --agree-to-license - - install-deps-python: - os: macos - - run: - name: Upgrade npm to satisfy package.json engine requirements (>=11.10) - command: npm install -g npm@^11.10 - - install-deps-alpine-full: - steps: - - run: - name: Installing Node.js + other test dependencies - command: | - arch=$(uname -m) - case "$arch" in - aarch64) arch="arm64";; - *) arch="amd64";; - esac - echo "using architecture: $arch" - apk add --update nodejs npm bash maven git python3 py3-pip elixir composer unzip xdg-utils docker - # apk's npm is < package.json engines floor (>=11.10); upgrade in place. - npm install -g npm@^11.10 - pip3 install pipenv requests PyYAML setuptools==70.3.0 - wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh && chmod +x dotnet-install.sh && ./dotnet-install.sh && \ - ln -s $HOME/.dotnet/dotnet /usr/local/bin/dotnet - wget https://go.dev/dl/go<< pipeline.parameters.go_version >>.linux-$arch.tar.gz -O /tmp/go.tgz && \ - tar -C /usr/local -xzvf /tmp/go.tgz && \ - ln -s /usr/local/go/bin/go /usr/local/bin - wget https://services.gradle.org/distributions/gradle-9.0.0-bin.zip -O /tmp/gradle.zip && \ - unzip -d /usr/local /tmp/gradle.zip && \ - ln -s /usr/local/gradle-9.0.0/bin/gradle /usr/local/bin - wget -qO- https://astral.sh/uv/install.sh | sh - ln -s $HOME/.local/bin/uv /usr/local/bin/uv - - failed-release-notification: - steps: - - when: - condition: - equal: [main, << pipeline.git.branch >>] - steps: - - run: - name: Handling failed release - command: bash ./release-scripts/handle-failed-release.sh - when: on_fail - - prepare-workspace: - parameters: - executor: - type: string - default: linux-base-edge-amd64 - steps: - - checkout - - attach_workspace: - at: . - - shall-deploy: - parameters: - deployment: - type: string - steps: + cat /tmp/continuation-config-path.txt - run: - name: Shall deployment be done - command: | - if [ "$(./release-scripts/skip-deployment.sh << parameters.deployment >>)" == true ]; then - echo The current branch does not deploy to \"<< parameters.deployment >>\" - circleci-agent step halt - fi - -#################################################################################################### -# WORKFLOWS -#################################################################################################### + name: Continue pipeline + command: ./scripts/ci/continue-pipeline.sh workflows: - test_and_release: + setup: jobs: - - prodsec/secrets-scan: - name: secrets-scan - context: snyk-bot-slack - channel: cli-alerts - trusted-branch: main - - - docs-only-check: - context: devex_cli_docker_hub - filters: - branches: - only: - - '/^docs\/.*/' - - - prepare-build: - context: - - devex_cli_docker_hub - - go-private-modules - requires: - - secrets-scan - filters: - branches: - ignore: - - '/^docs\/.*/' - - - code-analysis: - go_target_os: linux - go_os: linux - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - context: - - devex_cli - - devex_cli_docker_hub - - go-private-modules - requires: - - prepare-build - filters: - branches: - ignore: - - '/release.*/' - - - test-node: - context: - - nodejs-install - - team_hammerhead-cli - - devex_cli_docker_hub - requires: - - prepare-build - filters: - branches: - ignore: - - main - - '/release.*/' - - - test-go: - go_target_os: linux - go_os: linux - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - context: - - nodejs-install - - team_hammerhead-cli - - devex_cli_docker_hub - - go-private-modules - requires: - - prepare-build - filters: - branches: - ignore: - - main - - '/release.*/' - - - build-public: - name: build public (open source) - go_target_os: linux - go_os: linux - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - context: - - devex_cli_docker_hub - requires: - - secrets-scan - filters: - branches: - ignore: - - main - - '/release.*/' - - - test-legacy-tap: - context: - - nodejs-install - - team_hammerhead-cli - - devex_cli_docker_hub - requires: - - prepare-build - filters: - branches: - ignore: - - main - - '/release.*/' - - - build-special-artifacts: - name: build fix & protect - context: devex_cli_docker_hub - requires: - - prepare-build - - - build-artifact: - name: build linux amd64 - context: - - iac-cli - - go-private-modules - - devex_cli_docker_hub - go_target_os: linux - go_os: linux - go_arch: amd64 - static_binary: true - go_download_base_url: << pipeline.parameters.go_download_base_url >> - executor: docker-amd64-xl - requires: - - prepare-build - - - build-artifact: - name: build linux static amd64 - context: - - iac-cli - - go-private-modules - - devex_cli_docker_hub - go_target_os: linux - go_os: linux - go_arch: amd64 - static_binary: true - go_download_base_url: << pipeline.parameters.go_download_base_url >> - make_target: build-experimental BUILD_MODE=private - executor: docker-amd64-xl - requires: - - prepare-build - - - build-artifact: - name: build linux fips amd64 - context: - - iac-cli - - go-private-modules - - devex_cli_docker_hub - go_target_os: linux - go_os: linux - go_arch: amd64 - go_download_base_url: << pipeline.parameters.fips_go_download_base_url >> - make_target: build-fips BUILD_MODE=private - executor: docker-amd64-xl - requires: - - prepare-build - - - build-artifact: - name: build linux arm64 - context: - - iac-cli - - go-private-modules - - devex_cli_docker_hub - go_target_os: linux - go_os: linux - go_arch: arm64 - static_binary: true - go_download_base_url: << pipeline.parameters.go_download_base_url >> - executor: docker-arm64-xl - requires: - - prepare-build - - - build-artifact: - name: build linux static arm64 - context: - - iac-cli - - go-private-modules - - devex_cli_docker_hub - go_target_os: linux - go_os: linux - go_arch: arm64 - static_binary: true - go_download_base_url: << pipeline.parameters.go_download_base_url >> - make_target: build-experimental BUILD_MODE=private - executor: docker-arm64-xl - requires: - - prepare-build - - - build-artifact: - name: build linux fips arm64 - context: - - iac-cli - - go-private-modules - - devex_cli_docker_hub - go_target_os: linux - go_os: linux - go_arch: arm64 - go_download_base_url: << pipeline.parameters.fips_go_download_base_url >> - make_target: build-fips BUILD_MODE=private - executor: docker-arm64-xl - requires: - - prepare-build - - - build-artifact: - name: build alpine amd64 - context: - - iac-cli - - go-private-modules - - devex_cli_docker_hub - go_target_os: alpine - go_os: linux - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - executor: docker-amd64-xl - c_compiler: /usr/bin/musl-gcc - requires: - - prepare-build - - - build-artifact: - name: build alpine arm64 - context: - - iac-cli - - go-private-modules - - devex_cli_docker_hub - go_target_os: alpine - go_os: linux - go_arch: arm64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - executor: docker-arm64-xl - c_compiler: /usr/bin/musl-gcc - requires: - - prepare-build - - - build-artifact: - name: build macOS amd64 - go_target_os: darwin - go_os: darwin - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - executor: macos-arm64-large - install_deps_extension: macos-build - context: - - snyk-macos-signing - - iac-cli - - go-private-modules - requires: - - prepare-build - - - build-artifact: - name: build macOS arm64 - go_target_os: darwin - go_os: darwin - go_arch: arm64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - executor: macos-arm64-large - install_deps_extension: macos-build - context: - - snyk-macos-signing - - iac-cli - - go-private-modules - requires: - - prepare-build - - - build-artifact: - name: build windows amd64 - go_target_os: windows - go_os: windows - go_arch: amd64 - go_download_base_url: << pipeline.parameters.fips_go_download_base_url >> - make_target: build clean-golang build-fips BUILD_MODE=private - install_deps_extension: windows-native-full-signing - install_path: 'C:\' - executor: win-server2022-amd64 - context: - - snyk-windows-signing - - iac-cli - - go-private-modules - requires: - - prepare-build - - - acceptance-tests: - name: acceptance-tests linux static arm64 - go_target_os: linux - go_os: linux - go_arch: arm64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - shards: 6 - context: - - nodejs-install - - team_hammerhead-cli - - devex_cli_docker_hub - - team-cli-workflow-context - filters: - branches: - ignore: - - main - - '/release.*/' - pre_test_cmds: export BROWSER="curl -L" - requires: - - build linux static arm64 - executor: docker-arm64-xl - test_snyk_command: ./binary-releases/experimental/snyk-linux-arm64 - - - acceptance-tests: - name: acceptance-tests linux amd64 - go_target_os: linux - go_os: linux - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - shards: 6 - context: - - nodejs-install - - team_hammerhead-cli - - devex_cli_docker_hub - - team-cli-workflow-context - filters: - branches: - ignore: - - main - - '/release.*/' - pre_test_cmds: export BROWSER="curl -L" - requires: - - build linux amd64 - executor: docker-amd64-xl - test_snyk_command: ./binary-releases/snyk-linux - - - acceptance-tests: - name: acceptance-tests linux arm64 - go_target_os: linux - go_os: linux - go_arch: arm64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - shards: 6 - context: - - nodejs-install - - team_hammerhead-cli - - devex_cli_docker_hub - - team-cli-workflow-context - filters: - branches: - ignore: - - main - - '/release.*/' - pre_test_cmds: export BROWSER="curl -L" - requires: - - build linux arm64 - executor: docker-arm64 - test_snyk_command: ./binary-releases/snyk-linux-arm64 - - - acceptance-tests: - name: acceptance-tests fips linux arm64 - go_target_os: linux - go_os: linux - go_arch: arm64 - go_download_base_url: << pipeline.parameters.fips_go_download_base_url >> - shards: 6 - executor: docker-arm64 - test_snyk_command: ./binary-releases/fips/snyk-linux-arm64 - fips: 1 - context: - - nodejs-install - - team_hammerhead-cli - - devex_cli_docker_hub - - team-cli-workflow-context - filters: - branches: - ignore: - - main - - '/release.*/' - pre_test_cmds: export BROWSER="curl -L" - requires: - - build linux fips arm64 - - - acceptance-tests: - name: acceptance-tests alpine amd64 - go_target_os: alpine - go_os: linux - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - shards: 6 - context: - - nodejs-install - - team_hammerhead-cli - - team-cli-workflow-context - filters: - branches: - ignore: - - main - - '/release.*/' - requires: - - build alpine amd64 - executor: alpine - test_snyk_command: ./binary-releases/snyk-alpine - install_deps_extension: alpine-full - dont_skip_tests: 0 - pre_test_cmds: export BROWSER="wget -O -" - - - acceptance-tests: - name: acceptance-tests alpine arm64 - go_target_os: alpine - go_os: linux - go_arch: arm64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - shards: 6 - context: - - nodejs-install - - team_hammerhead-cli - - team-cli-workflow-context - filters: - branches: - ignore: - - main - - '/release.*/' - requires: - - build alpine arm64 - executor: alpine-arm64 - test_snyk_command: ./binary-releases/snyk-alpine-arm64 - install_deps_extension: alpine-full - dont_skip_tests: 0 - pre_test_cmds: export BROWSER="wget -O -" - - - acceptance-tests: - name: acceptance-tests macOS arm64 - go_target_os: darwin - go_os: darwin - go_arch: arm64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - shards: 6 - context: - - nodejs-install - - team_hammerhead-cli - - team-cli-workflow-context - filters: - branches: - ignore: - - main - - '/release.*/' - requires: - - build macOS arm64 - executor: macos-arm64 - test_snyk_command: ./binary-releases/snyk-macos-arm64 - install_deps_extension: macos-full - - - acceptance-tests: - name: acceptance-tests windows amd64 - go_target_os: windows - go_os: windows - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - context: - - nodejs-install - - team_hammerhead-cli - - team-cli-workflow-context - filters: - branches: - ignore: - - main - - '/release.*/' - requires: - - build windows amd64 - executor: win-server2022-amd64 - test_snyk_command: binary-releases\\snyk-win.exe - install_deps_extension: windows-native-build - dont_skip_tests: 0 - shards: 8 - pre_test_cmds: | - if (Test-Path '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>') { . '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>' } - test_cmd: | - Get-ChildItem -Recurse -Path test/jest/acceptance,ts-binary-wrapper/test/acceptance -Filter *.spec.ts | - ForEach-Object { (Resolve-Path -Relative $_.FullName) -replace '\\', '/' -replace '^\./', '' } | - circleci tests run --command "xargs npx jest --maxWorkers=1 --selectProjects coreCli --reporters=jest-junit --reporters=default --forceExit --" --split-by=timings --timings-type=file - - - sign: - name: sign windows amd64 - context: snyk-windows-signing - requires: - - build windows amd64 - go_os: windows - go_arch: amd64 - make_target: sign sign-fips - executor: win-server2022-amd64 - install_deps_extension: windows-native-full-signing - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - sign: - name: sign macos amd64 - context: snyk-macos-signing - requires: - - build macOS amd64 - go_os: darwin - go_arch: amd64 - executor: macos-arm64 - install_deps_extension: noop - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - sign: - name: sign macos arm64 - context: snyk-macos-signing - requires: - - build macOS arm64 - go_os: darwin - go_arch: arm64 - executor: macos-arm64 - install_deps_extension: noop - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - create_deployment_artifacts: - name: create deployment artifacts - go_target_os: linux - go_os: linux - go_arch: amd64 - go_download_base_url: << pipeline.parameters.go_download_base_url >> - context: - - snyk-cli-pgp-signing - - devex_cli_docker_hub - requires: - - sign macos amd64 - - sign macos arm64 - - sign windows amd64 - - build alpine amd64 - - build alpine arm64 - - build linux amd64 - - build linux arm64 - - build linux fips amd64 - - build linux fips arm64 - - build linux static amd64 - - build linux static arm64 - - build fix & protect - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - should-release: - name: release? - type: approval - requires: - - create deployment artifacts - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - pre-release: - name: upload version - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - requires: - - release? - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - npm-validation: - name: Validate NPM artifacts (<< matrix.executor >>) - context: - - team_hammerhead-cli - - devex_cli_docker_hub - matrix: - parameters: - executor: - - 'docker-amd64' - - 'win-server2019-amd64' - - 'macos-arm64' - requires: - - upload version - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - test-release: - name: e2e tests (<< matrix.executor >>) - context: - - team_hammerhead-cli - - devex_cli_docker_hub - matrix: - parameters: - executor: - - 'docker-amd64' - - 'docker-arm64' - - 'win-server2019-amd64' - - 'win-server2022-amd64' - - 'macos-arm64' - - 'linux-ubuntu-latest-amd64' - - 'linux-ubuntu-jammy-amd64' - - 'linux-ubuntu-focal-amd64' - - 'linux-ubuntu-latest-arm64' - - 'linux-ubuntu-jammy-arm64' - - 'linux-ubuntu-focal-arm64' - - 'alpine' - requires: - - upload version - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - test-release: - name: e2e experimental tests (linux-static-amd64) - context: team_hammerhead-cli - cli_download_base_url: << pipeline.parameters.experimental_cli_download_base_url >> - executor: 'linux-ubuntu-bionic-beaver-amd64' - requires: - - upload version - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - test-release: - name: e2e fips tests (suse-linux-fips) - context: team_hammerhead-cli - cli_download_base_url: << pipeline.parameters.fips_cli_download_base_url >> - setup_steps: - - run: zypper --non-interactive install python3-pip - executor: 'suse-linux-fips' - requires: - - upload version - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - test-release: - name: e2e fips tests (win-server2022-amd64) - context: team_hammerhead-cli - cli_download_base_url: << pipeline.parameters.fips_cli_download_base_url >> - setup_steps: - - run: Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy' -Name 'Enabled' -Value '1' - executor: 'win-server2022-amd64' - requires: - - upload version - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - test-release-static: - name: e2e experimental tests (scratch-container-amd64) - context: - - team_hammerhead-cli - requires: - - upload version - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - test-release-static: - name: e2e snyk-linux tests (scratch-container-amd64) - context: - - team_hammerhead-cli - requires: - - upload version - cli_download_base_url: << pipeline.parameters.cli_download_base_url >> - filters: - branches: - only: - - main - - '/release.*/' - - '/.*e2e.*/' - - - noop: - name: Start Deployments - requires: - - Validate NPM artifacts (docker-amd64) - - Validate NPM artifacts (win-server2019-amd64) - - Validate NPM artifacts (macos-arm64) - - e2e tests (docker-amd64) - - e2e tests (docker-arm64) - - e2e tests (win-server2019-amd64) - - e2e tests (win-server2022-amd64) - - e2e tests (macos-arm64) - - e2e tests (linux-ubuntu-latest-amd64) - - e2e tests (linux-ubuntu-jammy-amd64) - - e2e tests (linux-ubuntu-focal-amd64) - - e2e tests (linux-ubuntu-latest-arm64) - - e2e tests (linux-ubuntu-jammy-arm64) - - e2e tests (linux-ubuntu-focal-arm64) - - e2e tests (alpine) - - e2e fips tests (suse-linux-fips) - - e2e fips tests (win-server2022-amd64) - - e2e experimental tests (linux-static-amd64) - - e2e experimental tests (scratch-container-amd64) - - e2e snyk-linux tests (scratch-container-amd64) - filters: - branches: - only: - - main - - '/release.*/' - - - release-s3: - name: upload preview - deployment: preview - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - requires: - - Start Deployments - filters: - branches: - only: - - main - - '/release.*/' - - - release-s3: - name: upload release candidate - deployment: rc - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - requires: - - Start Deployments - filters: - branches: - only: - - main - - '/release.*/' - - - release-s3: - name: upload latest/stable - deployment: stable - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - requires: - - Start Deployments - filters: - branches: - only: - - main - - '/release.*/' - - - release-github: - name: upload github - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - requires: - - upload latest/stable - filters: - branches: - only: - - main - - '/release.*/' - - - release-npm: - name: upload npm (preview) - deployment: preview - context: - - devex_cli_docker_hub - requires: - - upload preview - filters: - branches: - only: - - main - - '/release.*/' - - - release-npm: - name: upload npm (rc) - deployment: rc - context: - - devex_cli_docker_hub - requires: - - upload release candidate - filters: - branches: - only: - - main - - '/release.*/' - - - release-npm: - name: upload npm - deployment: stable - context: - - devex_cli_docker_hub - requires: - - upload github - filters: - branches: - only: - - main - - '/release.*/' - - - trigger-building-distribution-channels: - name: Trigger building distribution channels (preview) - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - deployment: preview - requires: - - upload npm (preview) - filters: - branches: - only: - - main - - - trigger-building-distribution-channels: - name: Trigger building distribution channels (rc) - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - deployment: rc - requires: - - upload npm (rc) - filters: - branches: - only: - - '/release.*/' - - - trigger-building-distribution-channels: - name: Trigger building distribution channels (stable) - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - requires: - - upload npm - filters: - branches: - only: - - main - - '/release.*/' - - - trigger-build-agentic-integration: - name: Trigger building agentic-integration (stable) - context: - - team-hammerhead-common-deploy-tokens - - devex_cli_docker_hub - requires: - - upload npm - filters: - branches: - only: - - main - - '/release.*/' - -#################################################################################################### -# JOBS -#################################################################################################### - -jobs: - prepare-build: - executor: docker-amd64 - steps: - - checkout - - setup-go-private-modules - - restore_cache: - name: Restore npm cache - keys: - - prepare-v1-build-npm-deps-{{ checksum "package-lock.json" }} - - prepare-v1-build-npm-deps - - run: - name: Installing dependencies - command: npm ci --no-audit --no-progress --cache .npm --prefer-offline - - save_cache: - name: Save npm cache - key: prepare-v1-build-npm-deps-{{ checksum "package-lock.json" }} - paths: - - .npm - - run: - name: Set version - command: | - make binary-releases/version binary-releases/fips/version - make release-validate-version - make ts-cli-binaries/version BINARY_RELEASES_FOLDER_TS_CLI=ts-cli-binaries - - run: - # required for one unit test (ts-binary-wrapper/test/unit/common.spec.ts:15:30) - # consider removing this run - name: Pre-Build - command: make pre-build - - run: - name: Build TypeScript CLI - command: npm run build:prod - - persist_to_workspace: - root: . - paths: - - binary-releases/* - - ts-cli-binaries/* - - binary-releases/fips/* - - binary-releases/experimental/* - - node_modules/* - - ts-binary-wrapper/* - - dist/* - - packages/* - - code-analysis: - parameters: - go_os: - type: string - go_target_os: - type: string - go_arch: - type: string - go_download_base_url: - type: string - install_path: - type: string - default: '/tmp' - executor: docker-amd64 - steps: - - prepare-workspace - - install-go: - go_os: << parameters.go_os >> - go_target_os: << parameters.go_target_os >> - go_arch: << parameters.go_arch >> - base_url: << parameters.go_download_base_url >> - extraction_path: << parameters.install_path >> - - setup-go-private-modules - - run: - name: Linting project - command: make lint - - prodsec/security_scans: - mode: auto - open-source-additional-arguments: --exclude=test,dist - iac-scan: disabled - release-branch: main - open-source-scan-reachability: true - open-source-scan: high - - docs-only-check: - executor: docker-amd64 - steps: - - checkout - - run: - name: Check if all changed files are documentation (.md) - command: | - CHANGED_FILES=$(git diff --name-only main) - - # If this step fails, check if you need to add another extension, - # or indeed if this PR adds more than docs-related changes. - ALLOWED_DOCS_EXTENSIONS="(\.md|\.svg|\.jpg)$" - - for file in $CHANGED_FILES; do - echo "Checking extension of file: $file" - # -q: quiet - # -E: extended regular expressions - if ! echo "$file" | grep -q -E "$ALLOWED_DOCS_EXTENSIONS"; then - echo "Error: Disallowed file type found: $file" - exit 1 - fi - done - exit 0 - - test-node: - executor: docker-amd64 - environment: - JEST_JUNIT_OUTPUT_DIR: test/reports - steps: - - prepare-workspace - - run: - name: Running TS unit tests - command: npm run test:unit - - store_test_results: - path: test/reports - - test-go: - executor: docker-amd64 - parameters: - go_os: - type: string - go_target_os: - type: string - go_arch: - type: string - go_download_base_url: - type: string - install_path: - type: string - default: '.' - steps: - - prepare-workspace - - install-go: - go_os: << parameters.go_os >> - go_target_os: << parameters.go_target_os >> - go_arch: << parameters.go_arch >> - base_url: << parameters.go_download_base_url >> - extraction_path: << parameters.install_path >> - - setup-go-private-modules - - run: - name: Running Go unit tests - working_directory: ./cliv2 - command: make openboxtest - - build-public: - description: Verify the open source (public) CLI build compiles from scratch - executor: docker-amd64 - parameters: - go_os: - type: string - go_target_os: - type: string - go_arch: - type: string - go_download_base_url: - type: string - install_path: - type: string - default: '.' - steps: - - checkout - - restore_cache: - name: Restore npm cache (public build) - keys: - - public-build-npm-deps-{{ checksum "package-lock.json" }} - - public-build-npm-deps - - run: - name: Installing dependencies - command: npm ci --no-audit --no-progress --cache .npm --prefer-offline - - save_cache: - name: Save npm cache (public build) - key: public-build-npm-deps-{{ checksum "package-lock.json" }} - paths: - - .npm - - make-binary: - go_arch: << parameters.go_arch >> - go_target_os: << parameters.go_target_os >> - make_target: build BUILD_MODE=public - - run: - name: Verify public CLI runs and has -oss suffix - command: | - ./binary-releases/snyk-linux --version - ./binary-releases/snyk-linux --version 2>&1 | grep -q "\oss" || (echo "ERROR: Version should contain oss suffix for public build" && exit 1) - ./binary-releases/snyk-linux --help - - test-legacy-tap: - executor: docker-amd64 - parallelism: 3 - steps: - - prepare-workspace - - run: - name: Configuring artifact - command: node ./bin/snyk config set "api=${TEST_SNYK_TOKEN}" # many tests require the token to be in the config - - run: - name: Running Tap tests - no_output_timeout: '30m' # the whole set of tests regularly takes 25+ minutes. - command: > - npx tap -j 1 -C --timeout=300 -R junit --reporter-file=tap-junit.xml - --allow-incomplete-coverage - $(circleci tests glob "test/tap/*.test.*" | circleci tests split --split-by=timings) - - store_test_results: - path: tap-junit.xml - - build-special-artifacts: - executor: docker-amd64 - steps: - - prepare-workspace - - run: - name: Building snyk-fix.tgz - command: make binary-releases/snyk-fix.tgz - - run: - name: Building snyk-protect.tgz - command: make binary-releases/snyk-protect.tgz - - persist_to_workspace: - root: . - paths: - - binary-releases/snyk-fix.tgz - - binary-releases/snyk-protect.tgz - - build-artifact: - parameters: - go_os: - type: string - go_target_os: - type: string - go_arch: - type: string - static_binary: - type: boolean - default: false - c_compiler: - type: string - default: '' - executor: - type: string - go_download_base_url: - type: string - make_target: - type: string - default: 'build' - install_deps_extension: - type: string - default: 'noop' - install_path: - type: string - default: '.' - executor: << parameters.executor >> - steps: - - prepare-workspace - - install-deps-<< parameters.install_deps_extension >> - - install-go: - go_os: << parameters.go_os >> - go_target_os: << parameters.go_target_os >> - go_arch: << parameters.go_arch >> - base_url: << parameters.go_download_base_url >> - extraction_path: << parameters.install_path >> - - setup-go-private-modules - - restore_cache: - key: go-build-{{ arch }}-{{ checksum "cliv2/go.sum" }} - - make-binary: - static: << parameters.static_binary >> - go_arch: << parameters.go_arch >> - go_target_os: << parameters.go_target_os >> - make_target: << parameters.make_target >> - c_compiler: << parameters.c_compiler >> - - save_cache: - key: go-build-{{ arch }}-{{ checksum "cliv2/go.sum" }} - paths: [/home/circleci/go/pkg/mod] - - store_artifacts: - path: binary-releases - - persist_to_workspace: - root: . - paths: - - binary-releases/snyk-* - - binary-releases/fips/snyk-* - - binary-releases/experimental/snyk-* - - acceptance-tests: - parameters: - go_os: - type: string - go_target_os: - type: string - go_arch: - type: string - go_download_base_url: - type: string - install_path: - type: string - default: '.' - test_snyk_command: - type: string - executor: - type: string - fips: - type: integer - default: 0 - dont_skip_tests: - type: integer - default: 1 - install_deps_extension: - type: string - default: 'noop' - pre_test_cmds: - type: string - default: 'echo Running tests' - shards: - type: integer - default: 6 - test_cmd: - type: string - default: | - find test/jest/acceptance ts-binary-wrapper/test/acceptance -name '*.spec.ts' \ - | circleci tests run \ - --command="xargs npx jest --maxWorkers=1 --selectProjects coreCli --reporters=jest-junit --reporters=default --forceExit --" \ - --split-by=timings \ - --timings-type=file - executor: << parameters.executor >> - parallelism: << parameters.shards >> - environment: - PIP_BREAK_SYSTEM_PACKAGES: 1 - steps: - - prepare-workspace - - install-deps-<< parameters.install_deps_extension >> - - when: - condition: - matches: - pattern: '^(docker.*|alpine.*)' - value: << parameters.executor >> - steps: - - setup_remote_docker: - docker_layer_caching: false - - run: - command: npm install - - install-go: - go_os: << parameters.go_os >> - go_target_os: << parameters.go_target_os >> - go_arch: << parameters.go_arch >> - base_url: << parameters.go_download_base_url >> - extraction_path: << parameters.install_path >> - - run: - name: Running acceptance tests - no_output_timeout: 30m - command: | - << parameters.pre_test_cmds >> - << parameters.test_cmd >> - environment: - TEST_SNYK_FIPS: << parameters.fips >> - TEST_SNYK_COMMAND: << parameters.test_snyk_command >> - TEST_SNYK_DONT_SKIP_ANYTHING: << parameters.dont_skip_tests >> - JEST_JUNIT_OUTPUT_DIR: test/reports - NODE_OPTIONS: --max-old-space-size=4096 - - run: - name: Normalize junit file paths for timing data - when: always - command: node scripts/normalize-junit-file-paths.js test/reports - - store_test_results: - path: test/reports - - store_artifacts: - path: test/reports - - sign: - parameters: - go_os: - type: string - go_arch: - type: string - executor: - type: string - install_deps_extension: - type: string - make_target: - type: string - default: 'sign' - executor: << parameters.executor >> - steps: - - prepare-workspace - - install-deps-<< parameters.install_deps_extension >> - - run: - name: Signing << parameters.go_os >> artifact - command: make << parameters.make_target >> GOOS=<< parameters.go_os >> GOARCH=<< parameters.go_arch >> - - store_artifacts: - path: ./binary-releases - - persist_to_workspace: - root: . - paths: - - binary-releases/snyk-* - - binary-releases/fips/snyk-* - - binary-releases/experimental/snyk-* - - create_deployment_artifacts: - parameters: - go_os: - type: string - go_target_os: - type: string - go_arch: - type: string - go_download_base_url: - type: string - install_path: - type: string - default: '.' - executor: docker-amd64 - steps: - - prepare-workspace - - install-go: - go_os: << parameters.go_os >> - go_target_os: << parameters.go_target_os >> - go_arch: << parameters.go_arch >> - base_url: << parameters.go_download_base_url >> - extraction_path: << parameters.install_path >> - - run: - name: Creating all shasums - command: find binary-releases -name "snyk-*" -exec make {}.sha256 \; - - run: - name: Making TS-Binary-Wrapper (snyk.tgz) - command: make binary-releases/snyk.tgz - - run: - name: Signing all shasums - command: make binary-releases/sha256sums.txt.asc - - run: - name: Making release.json - command: make binary-releases/release.json - - run: - name: Making release notes - command: make binary-releases/RELEASE_NOTES.md binary-releases/fips/RELEASE_NOTES.md - - run: - name: Validating artifacts - command: ./release-scripts/validate-checksums.sh - - run: - name: Generate Protocol Version File - command: | - make ls-protocol-metadata - cp binary-releases/ls-protocol-version-* binary-releases/fips/ - cp binary-releases/ls-protocol-version-* binary-releases/experimental/ - - store_artifacts: - path: ./binary-releases - - persist_to_workspace: - root: . - paths: - - binary-releases/sha256sums.txt.asc - - binary-releases/release.json - - binary-releases/snyk-*.sha256 - - binary-releases/fips/sha256sums.txt.asc - - binary-releases/fips/release.json - - binary-releases/fips/snyk-*.sha256 - - binary-releases/RELEASE_NOTES.md - - binary-releases/snyk.tgz - - binary-releases/ls-protocol-version-* - - binary-releases/fips/ls-protocol-version-* - - binary-releases/fips/RELEASE_NOTES.md - - binary-releases/experimental/sha256sums.txt.asc - - binary-releases/experimental/snyk-*.sha256 - - binary-releases/experimental/ls-protocol-version-* - - pre-release: - executor: docker-amd64 - steps: - - prepare-workspace - - gh/setup: - token: HAMMERHEAD_GITHUB_PAT - version: << pipeline.parameters.gh_version >> - - aws-cli/install: - version: << pipeline.parameters.aws_version >> - - run: - name: Pre-Publishing - command: | - export NPM_ID_TOKEN=$(circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}') - make release-pre - - failed-release-notification - - npm-validation: - parameters: - executor: - type: string - executor: << parameters.executor >> - steps: - - prepare-workspace - - run: - name: Validating NPM artifacts - command: bash ./release-scripts/validate-npm-artifacts.sh - - failed-release-notification - - test-release: - parameters: - executor: - type: string - cli_download_base_url: - type: string - default: << pipeline.parameters.cli_download_base_url >> - setup_steps: - type: steps - default: [] - executor: << parameters.executor >> - steps: - - steps: << parameters.setup_steps >> - - prepare-workspace - - when: - condition: - matches: - pattern: '^macos.*' - value: << parameters.executor >> - steps: - - run: brew update && HOMEBREW_NO_ASK=1 brew install coreutils curl python3 - - when: - condition: - matches: - pattern: '^alpine' - value: << parameters.executor >> - steps: - - run: apk add python3 py3-pip bash - - when: - condition: - matches: - pattern: '^linux.*' - value: << parameters.executor >> - steps: - - run: | - export DEBIAN_FRONTEND=noninteractive - ln -fs /usr/share/zoneinfo/UTC /etc/localtime - apt update && apt install -y sudo curl python3 python3-pip python3-requests - - - run: - name: Checking Snyk CLI - shell: bash - environment: - SNYK_DISABLE_ANALYTICS: 1 - command: | - PIP_BREAK_SYSTEM_PACKAGES=1 pip install --user --upgrade requests || PIP_BREAK_SYSTEM_PACKAGES=1 pip3 install --user --upgrade requests - python scripts/install-snyk.py --base_url=<< parameters.cli_download_base_url >> $(cat binary-releases/version) || python3 scripts/install-snyk.py --base_url=<< parameters.cli_download_base_url >> $(cat binary-releases/version) - SNYK_TOKEN=${TEST_SNYK_TOKEN} ./snyk whoami --experimental - SNYK_TOKEN=${TEST_SNYK_TOKEN} ./snyk woof - - test-release-static: - parameters: - cli_download_base_url: - type: string - default: << pipeline.parameters.experimental_cli_download_base_url >> - executor: linux-machine-amd64 - steps: - - prepare-workspace - - run: - name: Build scratch test image - command: | - VERSION=$(cat binary-releases/version) - docker build \ - --build-arg CLI_DOWNLOAD_BASE_URL="<< parameters.cli_download_base_url >>" \ - --build-arg SNYK_VERSION="${VERSION}" \ - -f .circleci/Dockerfile.scratch-e2e \ - -t snyk-scratch-test . - - run: - name: Test Snyk CLI in scratch container - command: | - docker run --rm \ - -e SNYK_TOKEN="${TEST_SNYK_TOKEN}" \ - -e SNYK_DISABLE_ANALYTICS=1 \ - snyk-scratch-test \ - -c "/usr/local/bin/snyk whoami --experimental && /usr/local/bin/snyk woof" - - release-s3: - parameters: - deployment: - type: string - default: stable - executor: docker-amd64 - steps: - - prepare-workspace - - shall-deploy: - deployment: << parameters.deployment >> - - aws-cli/install: - version: << pipeline.parameters.aws_version >> - - run: - name: Publish to S3 ( << parameters.deployment >> ) - command: ./release-scripts/upload-artifacts.sh << parameters.deployment >> - - failed-release-notification - - release-github: - executor: docker-amd64 - steps: - - prepare-workspace - - shall-deploy: - deployment: stable - - gh/setup: - token: HAMMERHEAD_GITHUB_PAT - version: << pipeline.parameters.gh_version >> - - run: - name: Publish to GitHub - command: ./release-scripts/upload-artifacts.sh github - - run: - name: Create Jira Release - command: ./release-scripts/create-jira-release.sh - - failed-release-notification - - release-npm: - parameters: - deployment: - type: string - default: stable - executor: docker-amd64 - steps: - - prepare-workspace - - shall-deploy: - deployment: << parameters.deployment >> - - run: - name: Publish to npm ( << parameters.deployment >> ) - command: | - export NPM_ID_TOKEN=$(circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}') - ./release-scripts/upload-artifacts.sh npm - - failed-release-notification - - trigger-building-distribution-channels: - parameters: - deployment: - type: string - default: stable - executor: docker-amd64 - steps: - - prepare-workspace - - shall-deploy: - deployment: << parameters.deployment >> - - run: - name: Trigger build-and-publish workflow at snyk-images - command: ./release-scripts/upload-artifacts.sh trigger-distribution-channels - - failed-release-notification - - trigger-build-agentic-integration: - executor: docker-amd64 - steps: - - prepare-workspace - - run: - name: Trigger build-and-release workflow at agentic-integration-wrappers - command: ./release-scripts/upload-artifacts.sh trigger_build_agentic_integration - - failed-release-notification - - noop: - executor: generic-ubuntu - steps: - - run: - name: No operation - command: echo Nothing to be done! + - detect-code-changes diff --git a/.circleci/continue_config.yml b/.circleci/continue_config.yml new file mode 100644 index 0000000000..0b5be7238f --- /dev/null +++ b/.circleci/continue_config.yml @@ -0,0 +1,2054 @@ +version: 2.1 + +parameters: + cli_download_base_url: + type: string + default: 'https://downloads.snyk.io/' + fips_cli_download_base_url: + type: string + default: 'https://downloads.snyk.io/fips/' + experimental_cli_download_base_url: + type: string + default: 'https://downloads.snyk.io/experimental/' + go_download_base_url: + type: string + default: 'https://dl.google.com/go/' + fips_go_download_base_url: + type: string + default: 'https://aka.ms/golang/release/latest/' + go_version: + type: string + # https://go.dev/doc/devel/release + default: '1.26.4' + aws_version: + type: string + # https://github.com/aws/aws-cli/blob/v2/CHANGELOG.rst + default: '2.4.12' + gh_version: + type: string + # https://github.com/cli/cli/releases + default: '2.7.0' + windows_cache_dir: + type: string + default: 'C:\tools-cache' + windows_env_script: + type: string + default: 'snyk-env.ps1' + windows_bash_env_script: + type: string + default: 'snyk-env.sh' + +orbs: + prodsec: snyk/prodsec-orb@1 + snyk: snyk/snyk@2.0.3 + aws-cli: circleci/aws-cli@2.0.3 + gh: circleci/github-cli@2.1.0 + +executors: + alpine: + docker: + - image: alpine:3.23 + resource_class: xlarge + alpine-arm64: + docker: + - image: alpine:3.23 + resource_class: arm.xlarge + generic-ubuntu: + docker: + - image: ubuntu:latest + resource_class: small + linux-machine-amd64: + machine: + image: ubuntu-2204:current + resource_class: medium + docker-amd64: + docker: + - image: snyklabs/cli-build-private:20260610-125138 + auth: + username: $DOCKER_CLI_BUILD_USERNAME + password: $DOCKER_CLI_BUILD_PASSWORD + # working_directory: /mnt/ramdisk/snyk + resource_class: large + docker-amd64-xl: + docker: + - image: snyklabs/cli-build-private:20260610-125138 + auth: + username: $DOCKER_CLI_BUILD_USERNAME + password: $DOCKER_CLI_BUILD_PASSWORD + # working_directory: /mnt/ramdisk/snyk + resource_class: xlarge + docker-arm64: + docker: + - image: snyklabs/cli-build-private-arm64:20260610-125138 + auth: + username: $DOCKER_CLI_BUILD_USERNAME + password: $DOCKER_CLI_BUILD_PASSWORD + # working_directory: /mnt/ramdisk/snyk + resource_class: arm.large + docker-arm64-xl: + docker: + - image: snyklabs/cli-build-private-arm64:20260610-125138 + auth: + username: $DOCKER_CLI_BUILD_USERNAME + password: $DOCKER_CLI_BUILD_PASSWORD + # working_directory: /mnt/ramdisk/snyk + resource_class: arm.xlarge + linux-ubuntu-jammy-amd64: + docker: + - image: ubuntu:jammy + # working_directory: /mnt/ramdisk/snyk + resource_class: medium + linux-ubuntu-focal-amd64: + docker: + - image: ubuntu:focal + # working_directory: /mnt/ramdisk/snyk + resource_class: medium + linux-ubuntu-latest-amd64: + docker: + - image: ubuntu:latest + # working_directory: /mnt/ramdisk/snyk + resource_class: medium + linux-ubuntu-bionic-beaver-amd64: + docker: + - image: ubuntu:18.04 + # working_directory: /mnt/ramdisk/snyk + resource_class: medium + linux-ubuntu-latest-arm64: + docker: + - image: ubuntu:latest + # working_directory: /mnt/ramdisk/snyk + resource_class: arm.medium + linux-ubuntu-jammy-arm64: + docker: + - image: ubuntu:jammy + # working_directory: /mnt/ramdisk/snyk + resource_class: arm.medium + linux-ubuntu-focal-arm64: + docker: + - image: ubuntu:focal + # working_directory: /mnt/ramdisk/snyk + resource_class: arm.medium + macos-arm64: + macos: + # https://circleci.com/developer/machine/image/xcode#image-tags + xcode: '26.1.0' + resource_class: m4pro.medium + macos-arm64-large: + macos: + # https://circleci.com/developer/machine/image/xcode#image-tags + xcode: '26.1.0' + resource_class: m4pro.large + win-server2022-amd64: + machine: + image: windows-server-2022-gui:2024.01.1 + resource_class: windows.large + shell: powershell + win-server2019-amd64: + machine: + image: windows-server-2019-vs2019:2022.08.1 + resource_class: windows.medium + shell: powershell + cbl-mariner: + docker: + - image: mcr.microsoft.com/cbl-mariner/base/python:3.9.14-8-cm2.0.20240301-arm64 + resource_class: arm.medium + suse-linux-fips: + docker: + - image: registry.suse.com/bci/bci-base-fips:15.6 + resource_class: arm.medium + +commands: + make-binary: + parameters: + go_arch: + type: string + go_target_os: + type: string + make_target: + type: string + default: 'build BUILD_MODE=private' + c_compiler: + type: string + default: '' + static: + type: boolean + default: false + steps: + - when: + condition: << parameters.static >> + steps: + - run: + name: Build static << parameters.go_target_os >>/<< parameters.go_arch >> + shell: bash + environment: + CC: << parameters.c_compiler >> + MACOSX_DEPLOYMENT_TARGET: 13.0 + command: | + # load Windows $Env:Path values of tools necessary to execute the build (like Go) + if [ -f "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>" ]; then source "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>"; fi + make << parameters.make_target >> GOOS=<< parameters.go_target_os >> GOARCH=<< parameters.go_arch >> STATIC_NODE_BINARY=true CGO_ENABLED=0 + - unless: + condition: << parameters.static >> + steps: + - run: + name: Build << parameters.go_target_os >>/<< parameters.go_arch >> + shell: bash + environment: + CC: << parameters.c_compiler >> + MACOSX_DEPLOYMENT_TARGET: 13.0 + command: | + # load Windows $Env:Path values of tools necessary to execute the build (like Go) + if [ -f "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>" ]; then source "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>"; fi + make << parameters.make_target >> GOOS=<< parameters.go_target_os >> GOARCH=<< parameters.go_arch >> STATIC_NODE_BINARY=false CGO_ENABLED=1 + install-go: + parameters: + go_os: + type: string + go_target_os: + type: string + go_arch: + type: string + base_url: + type: string + extraction_path: + type: string + cache_key_file: + type: string + default: go_cache_key.txt + steps: + - run: + name: Create Cache Key + command: | + echo << parameters.extraction_path >>-<< parameters.base_url >>-<< parameters.go_target_os >>-<< parameters.go_arch >>-<< pipeline.parameters.go_version >> > << parameters.cache_key_file >> + cat << parameters.cache_key_file >> + - restore_cache: + name: Restoring go binary cache + keys: + - go-binary-cache-{{ checksum "<< parameters.cache_key_file >>" }} + - run: + name: Download go binary + command: python ./scripts/download_go.py << pipeline.parameters.go_version >> --go_os=<< parameters.go_os >> --go_arch=<< parameters.go_arch >> --base_url=<< parameters.base_url >> --extraction_path=<< parameters.extraction_path >> + - save_cache: + name: Caching go binary + key: go-binary-cache-{{ checksum "<< parameters.cache_key_file >>" }} + paths: + - << parameters.extraction_path >>/go + - unless: + condition: + equal: ['windows', << parameters.go_os >>] + steps: + - run: + name: Add go binary to PATH + command: echo "export PATH=$(realpath << parameters.extraction_path >>/go/bin):\$PATH" >> "$BASH_ENV" + - when: + condition: + equal: ['windows', << parameters.go_os >>] + steps: + - run: + name: Add go binary to PATH (via snyk-env) + shell: powershell + command: | + $goBin = '<< parameters.extraction_path >>\go\bin' + $envScript = '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>' + $bashEnvScript = '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_bash_env_script >>' + + if (-not (Test-Path $envScript)) { + New-Item -Path $envScript -ItemType File -Force | Out-Null + } + '$Env:Path = "' + $goBin + ';" + $Env:Path' | Out-File -FilePath $envScript -Append -Encoding UTF8 + + if (-not (Test-Path $bashEnvScript)) { + New-Item -Path $bashEnvScript -ItemType File -Force | Out-Null + } + $bashPath = $goBin.Replace('\', '/').Replace('C:', '/c') + $bashLine = 'export PATH="' + $bashPath + ':$PATH"' + [System.IO.File]::AppendAllText($bashEnvScript, $bashLine + "`n", (New-Object System.Text.UTF8Encoding $false)) + + install-deps-windows-native-build: + steps: + - run: + name: Ensure tools cache directory + shell: powershell + command: | + $cacheDir = '<< pipeline.parameters.windows_cache_dir >>' + if (-not (Test-Path $cacheDir)) { + New-Item -ItemType Directory -Path $cacheDir | Out-Null + } + - restore_cache: + name: Restoring Windows tools cache + keys: + - windows-tools-cache-v5-{{ arch }}-{{ checksum ".nvmrc" }} + - run: + name: Install Node.js (native) + shell: powershell + command: | + .\scripts\windows\install-node.ps1 + - run: + name: Install Apache Maven 3.8.2 (native) + shell: powershell + command: | + .\scripts\windows\install-maven.ps1 + - run: + name: Install Gradle 8.1.1 (native) + shell: powershell + command: | + .\scripts\windows\install-gradle.ps1 + - run: + name: Install .NET SDK 8.0.100 (native) + shell: powershell + command: | + .\scripts\windows\install-dotnet-sdk.ps1 + - run: + name: Install Python 3.12.8 (native) + shell: powershell + command: | + .\scripts\windows\install-python3.ps1 + - run: + name: Install GNU Make 4.4.1 (native) + shell: powershell + command: | + .\scripts\windows\install-make.ps1 + - run: + name: Ensure Python and uv + shell: powershell + command: | + if (Test-Path '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>') { . '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>' } + .\scripts\windows\ensure-python-uv.ps1 + - save_cache: + name: Saving Windows tools cache + key: windows-tools-cache-v5-{{ arch }}-{{ checksum ".nvmrc" }} + paths: + - << pipeline.parameters.windows_cache_dir >> + - C:\ProgramData\nvm + + install-deps-windows-native-full-signing: + steps: + - install-deps-windows-signing + - install-deps-windows-native-build + + install-deps-windows-signing: + steps: + - run: + name: Generate Cache Key + command: | + date +%U%Y >> ~/cache_key.txt + cat ~/cache_key.txt + - restore_cache: + name: Restoring DigitCert cache + keys: + - digicert-cache-v3-{{ arch }}-{{ checksum "~/cache_key.txt" }} + - run: + name: Install DigiCert Keylocker Tools + shell: powershell + command: | + # Navigate to C: drive + Set-Location C:\ + + # Check if the file exists in the user's home directory + $filePath = Join-Path $env:USERPROFILE 'smtools-windows-x64.msi' + if (Test-Path $filePath) { + Write-Host "File exists. Moving to C:" + Copy-Item $filePath -Destination .\ + } + else { + Write-Host "No existing file found. Downloading..." + # Download the file using Invoke-WebRequest + curl.exe -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:$env:SM_API_KEY" -o smtools-windows-x64.msi + # Copy the downloaded file to the user's home directory + Copy-Item 'smtools-windows-x64.msi' -Destination $env:USERPROFILE + } + + # Execute the MSI installer + msiexec.exe /i smtools-windows-x64.msi /quiet /qn | Wait-Process + & 'C:\Program Files\DigiCert\DigiCert One Signing Manager Tools\smksp_cert_sync.exe' + + # Manual resync + & 'C:\Program Files\DigiCert\DigiCert One Signing Manager Tools\smctl.exe' windows certsync + - save_cache: + name: Saving DigitCert cache + key: digicert-cache-v3-{{ arch }}-{{ checksum "~/cache_key.txt" }} + paths: + - ~\smtools-windows-x64.msi + + install-deps-windows-full-signing: + steps: + - install-deps-windows-signing + + install-deps-noop: + steps: + - run: + name: No dependencies to install + command: echo all done! + + setup-go-private-modules: + description: >- + Configure git and Go to fetch private snyk modules using the + GITHUB_PRIVATE_TOKEN provided by the `go-private-modules` context. + Safe to call on Linux, macOS and Windows (uses bash on all executors). + steps: + - run: + name: Configure access to private Snyk Go modules + shell: bash + command: | + # Load Windows env (PATH for git/go) if running on the Windows executor. + if [ -f "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>" ]; then + source "/c/tools-cache/<< pipeline.parameters.windows_bash_env_script >>" + fi + if [ -z "${GITHUB_PRIVATE_TOKEN}" ]; then + echo "GITHUB_PRIVATE_TOKEN is not set; skipping private Snyk modules setup." + echo "Add the 'go-private-modules' context to this job if private modules are required." + exit 0 + fi + git config --global url."https://${GITHUB_PRIVATE_TOKEN}:x-oauth-basic@github.com/snyk".insteadOf "https://github.com/snyk" + # Propagate GOPRIVATE to subsequent bash steps. + echo 'export GOPRIVATE=github.com/snyk' >> "$BASH_ENV" + + install-deps-python: + parameters: + os: + type: string + default: linux + modules: + type: string + default: requests PyYAML + steps: + - when: + condition: + matches: + pattern: '^(linux.*|macos.*|alpine.*|docker.*)' + value: << parameters.os >> + steps: + - run: + name: Installing python modules + command: python3 -m pip install << parameters.modules >> + - when: + condition: + matches: + pattern: '^(win.*|cbl-mariner.*)' + value: << parameters.os >> + steps: + - run: + shell: bash.exe + name: Installing python modules + command: python -m pip install << parameters.modules >> + + install-deps-macos-full: + parameters: + items: + type: string + default: go gradle python pipenv elixir composer gradle@9 maven dotnet uv + steps: + - run: + name: Installing Rosetta + command: softwareupdate --install-rosetta --agree-to-license + - run: + name: Update Homebrew + command: brew update + - restore_cache: + key: acceptance-tests-macos-<< parameters.items >> + - run: + name: Installing sdks and tools via homebrew + command: | + HOMEBREW_NO_ASK=1 brew install << parameters.items >> + echo 'export PATH="/opt/homebrew/opt/gradle@9/bin:$PATH"' >> "$BASH_ENV" + - save_cache: + key: acceptance-tests-macos-<< parameters.items >> + paths: + - ~/Library/Caches/Homebrew + - install-deps-python: + os: macos + - run: + name: Upgrade npm to satisfy package.json engine requirements (>=11.10) + command: npm install -g npm@^11.10 + - restore_cache: + keys: + - acceptance-{{ checksum "scripts/install-sbt.sh" }} + - run: + name: Installing sbt 1.x + command: ./scripts/install-sbt.sh + - save_cache: + key: acceptance-{{ checksum "scripts/install-sbt.sh" }} + paths: + - ~/sbt + + install-deps-macos-build: + parameters: + items: + type: string + default: go gradle python elixir composer gradle@9 maven sbt dotnet + steps: + - run: + name: Installing Rosetta + command: softwareupdate --install-rosetta --agree-to-license + - install-deps-python: + os: macos + - run: + name: Upgrade npm to satisfy package.json engine requirements (>=11.10) + command: npm install -g npm@^11.10 + + install-deps-alpine-full: + steps: + - run: + name: Installing Node.js + other test dependencies + command: | + arch=$(uname -m) + case "$arch" in + aarch64) arch="arm64";; + *) arch="amd64";; + esac + echo "using architecture: $arch" + apk add --update nodejs npm bash maven git python3 py3-pip elixir composer unzip xdg-utils docker + # apk's npm is < package.json engines floor (>=11.10); upgrade in place. + npm install -g npm@^11.10 + pip3 install pipenv requests PyYAML setuptools==70.3.0 + wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh && chmod +x dotnet-install.sh && ./dotnet-install.sh && \ + ln -s $HOME/.dotnet/dotnet /usr/local/bin/dotnet + wget https://go.dev/dl/go<< pipeline.parameters.go_version >>.linux-$arch.tar.gz -O /tmp/go.tgz && \ + tar -C /usr/local -xzvf /tmp/go.tgz && \ + ln -s /usr/local/go/bin/go /usr/local/bin + wget https://services.gradle.org/distributions/gradle-9.0.0-bin.zip -O /tmp/gradle.zip && \ + unzip -d /usr/local /tmp/gradle.zip && \ + ln -s /usr/local/gradle-9.0.0/bin/gradle /usr/local/bin + wget -qO- https://astral.sh/uv/install.sh | sh + ln -s $HOME/.local/bin/uv /usr/local/bin/uv + + failed-release-notification: + steps: + - when: + condition: + equal: [main, << pipeline.git.branch >>] + steps: + - run: + name: Handling failed release + command: bash ./release-scripts/handle-failed-release.sh + when: on_fail + + prepare-workspace: + parameters: + executor: + type: string + default: linux-base-edge-amd64 + steps: + - checkout + - attach_workspace: + at: . + + shall-deploy: + parameters: + deployment: + type: string + steps: + - run: + name: Shall deployment be done + command: | + if [ "$(./release-scripts/skip-deployment.sh << parameters.deployment >>)" == true ]; then + echo The current branch does not deploy to \"<< parameters.deployment >>\" + circleci-agent step halt + fi + +#################################################################################################### +# WORKFLOWS +#################################################################################################### + +workflows: + test_and_release: + jobs: + - prodsec/secrets-scan: + name: secrets-scan + context: snyk-bot-slack + channel: cli-alerts + trusted-branch: main + + - docs-only-check: + context: devex_cli_docker_hub + filters: + branches: + only: + - '/^docs\/.*/' + + - prepare-build: + context: + - devex_cli_docker_hub + - go-private-modules + requires: + - secrets-scan + filters: + branches: + ignore: + - '/^docs\/.*/' + + - code-analysis: + go_target_os: linux + go_os: linux + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + context: + - devex_cli + - devex_cli_docker_hub + - go-private-modules + requires: + - prepare-build + filters: + branches: + ignore: + - '/release.*/' + + - test-node: + context: + - nodejs-install + - team_hammerhead-cli + - devex_cli_docker_hub + requires: + - prepare-build + filters: + branches: + ignore: + - main + - '/release.*/' + + - test-go: + go_target_os: linux + go_os: linux + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + context: + - nodejs-install + - team_hammerhead-cli + - devex_cli_docker_hub + - go-private-modules + requires: + - prepare-build + filters: + branches: + ignore: + - main + - '/release.*/' + + - build-public: + name: build public (open source) + go_target_os: linux + go_os: linux + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + context: + - devex_cli_docker_hub + requires: + - secrets-scan + filters: + branches: + ignore: + - main + - '/release.*/' + + - test-legacy-tap: + context: + - nodejs-install + - team_hammerhead-cli + - devex_cli_docker_hub + requires: + - prepare-build + filters: + branches: + ignore: + - main + - '/release.*/' + + - build-special-artifacts: + name: build fix & protect + context: devex_cli_docker_hub + requires: + - prepare-build + + - build-artifact: + name: build linux amd64 + context: + - iac-cli + - go-private-modules + - devex_cli_docker_hub + go_target_os: linux + go_os: linux + go_arch: amd64 + static_binary: true + go_download_base_url: << pipeline.parameters.go_download_base_url >> + executor: docker-amd64-xl + requires: + - prepare-build + + - build-artifact: + name: build linux static amd64 + context: + - iac-cli + - go-private-modules + - devex_cli_docker_hub + go_target_os: linux + go_os: linux + go_arch: amd64 + static_binary: true + go_download_base_url: << pipeline.parameters.go_download_base_url >> + make_target: build-experimental BUILD_MODE=private + executor: docker-amd64-xl + requires: + - prepare-build + + - build-artifact: + name: build linux fips amd64 + context: + - iac-cli + - go-private-modules + - devex_cli_docker_hub + go_target_os: linux + go_os: linux + go_arch: amd64 + go_download_base_url: << pipeline.parameters.fips_go_download_base_url >> + make_target: build-fips BUILD_MODE=private + executor: docker-amd64-xl + requires: + - prepare-build + + - build-artifact: + name: build linux arm64 + context: + - iac-cli + - go-private-modules + - devex_cli_docker_hub + go_target_os: linux + go_os: linux + go_arch: arm64 + static_binary: true + go_download_base_url: << pipeline.parameters.go_download_base_url >> + executor: docker-arm64-xl + requires: + - prepare-build + + - build-artifact: + name: build linux static arm64 + context: + - iac-cli + - go-private-modules + - devex_cli_docker_hub + go_target_os: linux + go_os: linux + go_arch: arm64 + static_binary: true + go_download_base_url: << pipeline.parameters.go_download_base_url >> + make_target: build-experimental BUILD_MODE=private + executor: docker-arm64-xl + requires: + - prepare-build + + - build-artifact: + name: build linux fips arm64 + context: + - iac-cli + - go-private-modules + - devex_cli_docker_hub + go_target_os: linux + go_os: linux + go_arch: arm64 + go_download_base_url: << pipeline.parameters.fips_go_download_base_url >> + make_target: build-fips BUILD_MODE=private + executor: docker-arm64-xl + requires: + - prepare-build + + - build-artifact: + name: build alpine amd64 + context: + - iac-cli + - go-private-modules + - devex_cli_docker_hub + go_target_os: alpine + go_os: linux + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + executor: docker-amd64-xl + c_compiler: /usr/bin/musl-gcc + requires: + - prepare-build + + - build-artifact: + name: build alpine arm64 + context: + - iac-cli + - go-private-modules + - devex_cli_docker_hub + go_target_os: alpine + go_os: linux + go_arch: arm64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + executor: docker-arm64-xl + c_compiler: /usr/bin/musl-gcc + requires: + - prepare-build + + - build-artifact: + name: build macOS amd64 + go_target_os: darwin + go_os: darwin + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + executor: macos-arm64-large + install_deps_extension: macos-build + context: + - snyk-macos-signing + - iac-cli + - go-private-modules + requires: + - prepare-build + + - build-artifact: + name: build macOS arm64 + go_target_os: darwin + go_os: darwin + go_arch: arm64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + executor: macos-arm64-large + install_deps_extension: macos-build + context: + - snyk-macos-signing + - iac-cli + - go-private-modules + requires: + - prepare-build + + - build-artifact: + name: build windows amd64 + go_target_os: windows + go_os: windows + go_arch: amd64 + go_download_base_url: << pipeline.parameters.fips_go_download_base_url >> + make_target: build clean-golang build-fips BUILD_MODE=private + install_deps_extension: windows-native-full-signing + install_path: 'C:\' + executor: win-server2022-amd64 + context: + - snyk-windows-signing + - iac-cli + - go-private-modules + requires: + - prepare-build + + - acceptance-tests: + name: acceptance-tests linux static arm64 + go_target_os: linux + go_os: linux + go_arch: arm64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + shards: 6 + context: + - nodejs-install + - team_hammerhead-cli + - devex_cli_docker_hub + - team-cli-workflow-context + filters: + branches: + ignore: + - main + - '/release.*/' + pre_test_cmds: export BROWSER="curl -L" + requires: + - build linux static arm64 + executor: docker-arm64-xl + test_snyk_command: ./binary-releases/experimental/snyk-linux-arm64 + + - acceptance-tests: + name: acceptance-tests linux amd64 + go_target_os: linux + go_os: linux + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + shards: 6 + context: + - nodejs-install + - team_hammerhead-cli + - devex_cli_docker_hub + - team-cli-workflow-context + filters: + branches: + ignore: + - main + - '/release.*/' + pre_test_cmds: export BROWSER="curl -L" + requires: + - build linux amd64 + executor: docker-amd64-xl + test_snyk_command: ./binary-releases/snyk-linux + + - acceptance-tests: + name: acceptance-tests linux arm64 + go_target_os: linux + go_os: linux + go_arch: arm64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + shards: 6 + context: + - nodejs-install + - team_hammerhead-cli + - devex_cli_docker_hub + - team-cli-workflow-context + filters: + branches: + ignore: + - main + - '/release.*/' + pre_test_cmds: export BROWSER="curl -L" + requires: + - build linux arm64 + executor: docker-arm64 + test_snyk_command: ./binary-releases/snyk-linux-arm64 + + - acceptance-tests: + name: acceptance-tests fips linux arm64 + go_target_os: linux + go_os: linux + go_arch: arm64 + go_download_base_url: << pipeline.parameters.fips_go_download_base_url >> + shards: 6 + executor: docker-arm64 + test_snyk_command: ./binary-releases/fips/snyk-linux-arm64 + fips: 1 + context: + - nodejs-install + - team_hammerhead-cli + - devex_cli_docker_hub + - team-cli-workflow-context + filters: + branches: + ignore: + - main + - '/release.*/' + pre_test_cmds: export BROWSER="curl -L" + requires: + - build linux fips arm64 + + - acceptance-tests: + name: acceptance-tests alpine amd64 + go_target_os: alpine + go_os: linux + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + shards: 6 + context: + - nodejs-install + - team_hammerhead-cli + - team-cli-workflow-context + filters: + branches: + ignore: + - main + - '/release.*/' + requires: + - build alpine amd64 + executor: alpine + test_snyk_command: ./binary-releases/snyk-alpine + install_deps_extension: alpine-full + dont_skip_tests: 0 + pre_test_cmds: export BROWSER="wget -O -" + + - acceptance-tests: + name: acceptance-tests alpine arm64 + go_target_os: alpine + go_os: linux + go_arch: arm64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + shards: 6 + context: + - nodejs-install + - team_hammerhead-cli + - team-cli-workflow-context + filters: + branches: + ignore: + - main + - '/release.*/' + requires: + - build alpine arm64 + executor: alpine-arm64 + test_snyk_command: ./binary-releases/snyk-alpine-arm64 + install_deps_extension: alpine-full + dont_skip_tests: 0 + pre_test_cmds: export BROWSER="wget -O -" + + - acceptance-tests: + name: acceptance-tests macOS arm64 + go_target_os: darwin + go_os: darwin + go_arch: arm64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + shards: 6 + context: + - nodejs-install + - team_hammerhead-cli + - team-cli-workflow-context + filters: + branches: + ignore: + - main + - '/release.*/' + requires: + - build macOS arm64 + executor: macos-arm64 + test_snyk_command: ./binary-releases/snyk-macos-arm64 + install_deps_extension: macos-full + + - acceptance-tests: + name: acceptance-tests windows amd64 + go_target_os: windows + go_os: windows + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + context: + - nodejs-install + - team_hammerhead-cli + - team-cli-workflow-context + filters: + branches: + ignore: + - main + - '/release.*/' + requires: + - build windows amd64 + executor: win-server2022-amd64 + test_snyk_command: binary-releases\\snyk-win.exe + install_deps_extension: windows-native-build + dont_skip_tests: 0 + shards: 8 + pre_test_cmds: | + if (Test-Path '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>') { . '<< pipeline.parameters.windows_cache_dir >>/<< pipeline.parameters.windows_env_script >>' } + test_cmd: | + Get-ChildItem -Recurse -Path test/jest/acceptance,ts-binary-wrapper/test/acceptance -Filter *.spec.ts | + ForEach-Object { (Resolve-Path -Relative $_.FullName) -replace '\\', '/' -replace '^\./', '' } | + circleci tests run --command "xargs npx jest --maxWorkers=1 --selectProjects coreCli --reporters=jest-junit --reporters=default --forceExit --" --split-by=timings --timings-type=file + + - sign: + name: sign windows amd64 + context: snyk-windows-signing + requires: + - build windows amd64 + go_os: windows + go_arch: amd64 + make_target: sign sign-fips + executor: win-server2022-amd64 + install_deps_extension: windows-native-full-signing + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - sign: + name: sign macos amd64 + context: snyk-macos-signing + requires: + - build macOS amd64 + go_os: darwin + go_arch: amd64 + executor: macos-arm64 + install_deps_extension: noop + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - sign: + name: sign macos arm64 + context: snyk-macos-signing + requires: + - build macOS arm64 + go_os: darwin + go_arch: arm64 + executor: macos-arm64 + install_deps_extension: noop + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - create_deployment_artifacts: + name: create deployment artifacts + go_target_os: linux + go_os: linux + go_arch: amd64 + go_download_base_url: << pipeline.parameters.go_download_base_url >> + context: + - snyk-cli-pgp-signing + - devex_cli_docker_hub + requires: + - sign macos amd64 + - sign macos arm64 + - sign windows amd64 + - build alpine amd64 + - build alpine arm64 + - build linux amd64 + - build linux arm64 + - build linux fips amd64 + - build linux fips arm64 + - build linux static amd64 + - build linux static arm64 + - build fix & protect + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - should-release: + name: release? + type: approval + requires: + - create deployment artifacts + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - pre-release: + name: upload version + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + requires: + - release? + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - npm-validation: + name: Validate NPM artifacts (<< matrix.executor >>) + context: + - team_hammerhead-cli + - devex_cli_docker_hub + matrix: + parameters: + executor: + - 'docker-amd64' + - 'win-server2019-amd64' + - 'macos-arm64' + requires: + - upload version + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - test-release: + name: e2e tests (<< matrix.executor >>) + context: + - team_hammerhead-cli + - devex_cli_docker_hub + matrix: + parameters: + executor: + - 'docker-amd64' + - 'docker-arm64' + - 'win-server2019-amd64' + - 'win-server2022-amd64' + - 'macos-arm64' + - 'linux-ubuntu-latest-amd64' + - 'linux-ubuntu-jammy-amd64' + - 'linux-ubuntu-focal-amd64' + - 'linux-ubuntu-latest-arm64' + - 'linux-ubuntu-jammy-arm64' + - 'linux-ubuntu-focal-arm64' + - 'alpine' + requires: + - upload version + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - test-release: + name: e2e experimental tests (linux-static-amd64) + context: team_hammerhead-cli + cli_download_base_url: << pipeline.parameters.experimental_cli_download_base_url >> + executor: 'linux-ubuntu-bionic-beaver-amd64' + requires: + - upload version + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - test-release: + name: e2e fips tests (suse-linux-fips) + context: team_hammerhead-cli + cli_download_base_url: << pipeline.parameters.fips_cli_download_base_url >> + setup_steps: + - run: zypper --non-interactive install python3-pip + executor: 'suse-linux-fips' + requires: + - upload version + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - test-release: + name: e2e fips tests (win-server2022-amd64) + context: team_hammerhead-cli + cli_download_base_url: << pipeline.parameters.fips_cli_download_base_url >> + setup_steps: + - run: Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy' -Name 'Enabled' -Value '1' + executor: 'win-server2022-amd64' + requires: + - upload version + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - test-release-static: + name: e2e experimental tests (scratch-container-amd64) + context: + - team_hammerhead-cli + requires: + - upload version + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - test-release-static: + name: e2e snyk-linux tests (scratch-container-amd64) + context: + - team_hammerhead-cli + requires: + - upload version + cli_download_base_url: << pipeline.parameters.cli_download_base_url >> + filters: + branches: + only: + - main + - '/release.*/' + - '/.*e2e.*/' + + - noop: + name: Start Deployments + requires: + - Validate NPM artifacts (docker-amd64) + - Validate NPM artifacts (win-server2019-amd64) + - Validate NPM artifacts (macos-arm64) + - e2e tests (docker-amd64) + - e2e tests (docker-arm64) + - e2e tests (win-server2019-amd64) + - e2e tests (win-server2022-amd64) + - e2e tests (macos-arm64) + - e2e tests (linux-ubuntu-latest-amd64) + - e2e tests (linux-ubuntu-jammy-amd64) + - e2e tests (linux-ubuntu-focal-amd64) + - e2e tests (linux-ubuntu-latest-arm64) + - e2e tests (linux-ubuntu-jammy-arm64) + - e2e tests (linux-ubuntu-focal-arm64) + - e2e tests (alpine) + - e2e fips tests (suse-linux-fips) + - e2e fips tests (win-server2022-amd64) + - e2e experimental tests (linux-static-amd64) + - e2e experimental tests (scratch-container-amd64) + - e2e snyk-linux tests (scratch-container-amd64) + filters: + branches: + only: + - main + - '/release.*/' + + - release-s3: + name: upload preview + deployment: preview + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + requires: + - Start Deployments + filters: + branches: + only: + - main + - '/release.*/' + + - release-s3: + name: upload release candidate + deployment: rc + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + requires: + - Start Deployments + filters: + branches: + only: + - main + - '/release.*/' + + - release-s3: + name: upload latest/stable + deployment: stable + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + requires: + - Start Deployments + filters: + branches: + only: + - main + - '/release.*/' + + - release-github: + name: upload github + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + requires: + - upload latest/stable + filters: + branches: + only: + - main + - '/release.*/' + + - release-npm: + name: upload npm (preview) + deployment: preview + context: + - devex_cli_docker_hub + requires: + - upload preview + filters: + branches: + only: + - main + - '/release.*/' + + - release-npm: + name: upload npm (rc) + deployment: rc + context: + - devex_cli_docker_hub + requires: + - upload release candidate + filters: + branches: + only: + - main + - '/release.*/' + + - release-npm: + name: upload npm + deployment: stable + context: + - devex_cli_docker_hub + requires: + - upload github + filters: + branches: + only: + - main + - '/release.*/' + + - trigger-building-distribution-channels: + name: Trigger building distribution channels (preview) + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + deployment: preview + requires: + - upload npm (preview) + filters: + branches: + only: + - main + + - trigger-building-distribution-channels: + name: Trigger building distribution channels (rc) + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + deployment: rc + requires: + - upload npm (rc) + filters: + branches: + only: + - '/release.*/' + + - trigger-building-distribution-channels: + name: Trigger building distribution channels (stable) + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + requires: + - upload npm + filters: + branches: + only: + - main + - '/release.*/' + + - trigger-build-agentic-integration: + name: Trigger building agentic-integration (stable) + context: + - team-hammerhead-common-deploy-tokens + - devex_cli_docker_hub + requires: + - upload npm + filters: + branches: + only: + - main + - '/release.*/' + +#################################################################################################### +# JOBS +#################################################################################################### + +jobs: + prepare-build: + executor: docker-amd64 + steps: + - checkout + - setup-go-private-modules + - restore_cache: + name: Restore npm cache + keys: + - prepare-v1-build-npm-deps-{{ checksum "package-lock.json" }} + - prepare-v1-build-npm-deps + - run: + name: Installing dependencies + command: npm ci --no-audit --no-progress --cache .npm --prefer-offline + - save_cache: + name: Save npm cache + key: prepare-v1-build-npm-deps-{{ checksum "package-lock.json" }} + paths: + - .npm + - run: + name: Set version + command: | + make binary-releases/version binary-releases/fips/version + make release-validate-version + make ts-cli-binaries/version BINARY_RELEASES_FOLDER_TS_CLI=ts-cli-binaries + - run: + # required for one unit test (ts-binary-wrapper/test/unit/common.spec.ts:15:30) + # consider removing this run + name: Pre-Build + command: make pre-build + - run: + name: Build TypeScript CLI + command: npm run build:prod + - persist_to_workspace: + root: . + paths: + - binary-releases/* + - ts-cli-binaries/* + - binary-releases/fips/* + - binary-releases/experimental/* + - node_modules/* + - ts-binary-wrapper/* + - dist/* + - packages/* + + code-analysis: + parameters: + go_os: + type: string + go_target_os: + type: string + go_arch: + type: string + go_download_base_url: + type: string + install_path: + type: string + default: '/tmp' + executor: docker-amd64 + steps: + - prepare-workspace + - install-go: + go_os: << parameters.go_os >> + go_target_os: << parameters.go_target_os >> + go_arch: << parameters.go_arch >> + base_url: << parameters.go_download_base_url >> + extraction_path: << parameters.install_path >> + - setup-go-private-modules + - run: + name: Linting project + command: make lint + - prodsec/security_scans: + mode: auto + open-source-additional-arguments: --exclude=test,dist + iac-scan: disabled + release-branch: main + open-source-scan-reachability: true + open-source-scan: high + + docs-only-check: + executor: docker-amd64 + steps: + - checkout + - run: + name: Fetch base branch + command: git fetch origin main --depth=100 + - run: + name: Check if all changed files are documentation + command: ./scripts/ci/is-docs-only-changes.sh + + test-node: + executor: docker-amd64 + environment: + JEST_JUNIT_OUTPUT_DIR: test/reports + steps: + - prepare-workspace + - run: + name: Running TS unit tests + command: npm run test:unit + - store_test_results: + path: test/reports + + test-go: + executor: docker-amd64 + parameters: + go_os: + type: string + go_target_os: + type: string + go_arch: + type: string + go_download_base_url: + type: string + install_path: + type: string + default: '.' + steps: + - prepare-workspace + - install-go: + go_os: << parameters.go_os >> + go_target_os: << parameters.go_target_os >> + go_arch: << parameters.go_arch >> + base_url: << parameters.go_download_base_url >> + extraction_path: << parameters.install_path >> + - setup-go-private-modules + - run: + name: Running Go unit tests + working_directory: ./cliv2 + command: make openboxtest + + build-public: + description: Verify the open source (public) CLI build compiles from scratch + executor: docker-amd64 + parameters: + go_os: + type: string + go_target_os: + type: string + go_arch: + type: string + go_download_base_url: + type: string + install_path: + type: string + default: '.' + steps: + - checkout + - restore_cache: + name: Restore npm cache (public build) + keys: + - public-build-npm-deps-{{ checksum "package-lock.json" }} + - public-build-npm-deps + - run: + name: Installing dependencies + command: npm ci --no-audit --no-progress --cache .npm --prefer-offline + - save_cache: + name: Save npm cache (public build) + key: public-build-npm-deps-{{ checksum "package-lock.json" }} + paths: + - .npm + - make-binary: + go_arch: << parameters.go_arch >> + go_target_os: << parameters.go_target_os >> + make_target: build BUILD_MODE=public + - run: + name: Verify public CLI runs and has -oss suffix + command: | + ./binary-releases/snyk-linux --version + ./binary-releases/snyk-linux --version 2>&1 | grep -q "\oss" || (echo "ERROR: Version should contain oss suffix for public build" && exit 1) + ./binary-releases/snyk-linux --help + + test-legacy-tap: + executor: docker-amd64 + parallelism: 3 + steps: + - prepare-workspace + - run: + name: Configuring artifact + command: node ./bin/snyk config set "api=${TEST_SNYK_TOKEN}" # many tests require the token to be in the config + - run: + name: Running Tap tests + no_output_timeout: '30m' # the whole set of tests regularly takes 25+ minutes. + command: > + npx tap -j 1 -C --timeout=300 -R junit --reporter-file=tap-junit.xml + --allow-incomplete-coverage + $(circleci tests glob "test/tap/*.test.*" | circleci tests split --split-by=timings) + - store_test_results: + path: tap-junit.xml + + build-special-artifacts: + executor: docker-amd64 + steps: + - prepare-workspace + - run: + name: Building snyk-fix.tgz + command: make binary-releases/snyk-fix.tgz + - run: + name: Building snyk-protect.tgz + command: make binary-releases/snyk-protect.tgz + - persist_to_workspace: + root: . + paths: + - binary-releases/snyk-fix.tgz + - binary-releases/snyk-protect.tgz + + build-artifact: + parameters: + go_os: + type: string + go_target_os: + type: string + go_arch: + type: string + static_binary: + type: boolean + default: false + c_compiler: + type: string + default: '' + executor: + type: string + go_download_base_url: + type: string + make_target: + type: string + default: 'build' + install_deps_extension: + type: string + default: 'noop' + install_path: + type: string + default: '.' + executor: << parameters.executor >> + steps: + - prepare-workspace + - install-deps-<< parameters.install_deps_extension >> + - install-go: + go_os: << parameters.go_os >> + go_target_os: << parameters.go_target_os >> + go_arch: << parameters.go_arch >> + base_url: << parameters.go_download_base_url >> + extraction_path: << parameters.install_path >> + - setup-go-private-modules + - restore_cache: + key: go-build-{{ arch }}-{{ checksum "cliv2/go.sum" }} + - make-binary: + static: << parameters.static_binary >> + go_arch: << parameters.go_arch >> + go_target_os: << parameters.go_target_os >> + make_target: << parameters.make_target >> + c_compiler: << parameters.c_compiler >> + - save_cache: + key: go-build-{{ arch }}-{{ checksum "cliv2/go.sum" }} + paths: [/home/circleci/go/pkg/mod] + - store_artifacts: + path: binary-releases + - persist_to_workspace: + root: . + paths: + - binary-releases/snyk-* + - binary-releases/fips/snyk-* + - binary-releases/experimental/snyk-* + + acceptance-tests: + parameters: + go_os: + type: string + go_target_os: + type: string + go_arch: + type: string + go_download_base_url: + type: string + install_path: + type: string + default: '.' + test_snyk_command: + type: string + executor: + type: string + fips: + type: integer + default: 0 + dont_skip_tests: + type: integer + default: 1 + install_deps_extension: + type: string + default: 'noop' + pre_test_cmds: + type: string + default: 'echo Running tests' + shards: + type: integer + default: 6 + test_cmd: + type: string + default: | + find test/jest/acceptance ts-binary-wrapper/test/acceptance -name '*.spec.ts' \ + | circleci tests run \ + --command="xargs npx jest --maxWorkers=1 --selectProjects coreCli --reporters=jest-junit --reporters=default --forceExit --" \ + --split-by=timings \ + --timings-type=file + executor: << parameters.executor >> + parallelism: << parameters.shards >> + environment: + PIP_BREAK_SYSTEM_PACKAGES: 1 + steps: + - prepare-workspace + - install-deps-<< parameters.install_deps_extension >> + - when: + condition: + matches: + pattern: '^(docker.*|alpine.*)' + value: << parameters.executor >> + steps: + - setup_remote_docker: + docker_layer_caching: false + - run: + command: npm install + - install-go: + go_os: << parameters.go_os >> + go_target_os: << parameters.go_target_os >> + go_arch: << parameters.go_arch >> + base_url: << parameters.go_download_base_url >> + extraction_path: << parameters.install_path >> + - run: + name: Running acceptance tests + no_output_timeout: 30m + command: | + << parameters.pre_test_cmds >> + << parameters.test_cmd >> + environment: + TEST_SNYK_FIPS: << parameters.fips >> + TEST_SNYK_COMMAND: << parameters.test_snyk_command >> + TEST_SNYK_DONT_SKIP_ANYTHING: << parameters.dont_skip_tests >> + JEST_JUNIT_OUTPUT_DIR: test/reports + NODE_OPTIONS: --max-old-space-size=4096 + - run: + name: Normalize junit file paths for timing data + when: always + command: node scripts/normalize-junit-file-paths.js test/reports + - store_test_results: + path: test/reports + - store_artifacts: + path: test/reports + + sign: + parameters: + go_os: + type: string + go_arch: + type: string + executor: + type: string + install_deps_extension: + type: string + make_target: + type: string + default: 'sign' + executor: << parameters.executor >> + steps: + - prepare-workspace + - install-deps-<< parameters.install_deps_extension >> + - run: + name: Signing << parameters.go_os >> artifact + command: make << parameters.make_target >> GOOS=<< parameters.go_os >> GOARCH=<< parameters.go_arch >> + - store_artifacts: + path: ./binary-releases + - persist_to_workspace: + root: . + paths: + - binary-releases/snyk-* + - binary-releases/fips/snyk-* + - binary-releases/experimental/snyk-* + + create_deployment_artifacts: + parameters: + go_os: + type: string + go_target_os: + type: string + go_arch: + type: string + go_download_base_url: + type: string + install_path: + type: string + default: '.' + executor: docker-amd64 + steps: + - prepare-workspace + - install-go: + go_os: << parameters.go_os >> + go_target_os: << parameters.go_target_os >> + go_arch: << parameters.go_arch >> + base_url: << parameters.go_download_base_url >> + extraction_path: << parameters.install_path >> + - run: + name: Creating all shasums + command: find binary-releases -name "snyk-*" -exec make {}.sha256 \; + - run: + name: Making TS-Binary-Wrapper (snyk.tgz) + command: make binary-releases/snyk.tgz + - run: + name: Signing all shasums + command: make binary-releases/sha256sums.txt.asc + - run: + name: Making release.json + command: make binary-releases/release.json + - run: + name: Making release notes + command: make binary-releases/RELEASE_NOTES.md binary-releases/fips/RELEASE_NOTES.md + - run: + name: Validating artifacts + command: ./release-scripts/validate-checksums.sh + - run: + name: Generate Protocol Version File + command: | + make ls-protocol-metadata + cp binary-releases/ls-protocol-version-* binary-releases/fips/ + cp binary-releases/ls-protocol-version-* binary-releases/experimental/ + - store_artifacts: + path: ./binary-releases + - persist_to_workspace: + root: . + paths: + - binary-releases/sha256sums.txt.asc + - binary-releases/release.json + - binary-releases/snyk-*.sha256 + - binary-releases/fips/sha256sums.txt.asc + - binary-releases/fips/release.json + - binary-releases/fips/snyk-*.sha256 + - binary-releases/RELEASE_NOTES.md + - binary-releases/snyk.tgz + - binary-releases/ls-protocol-version-* + - binary-releases/fips/ls-protocol-version-* + - binary-releases/fips/RELEASE_NOTES.md + - binary-releases/experimental/sha256sums.txt.asc + - binary-releases/experimental/snyk-*.sha256 + - binary-releases/experimental/ls-protocol-version-* + + pre-release: + executor: docker-amd64 + steps: + - prepare-workspace + - gh/setup: + token: HAMMERHEAD_GITHUB_PAT + version: << pipeline.parameters.gh_version >> + - aws-cli/install: + version: << pipeline.parameters.aws_version >> + - run: + name: Pre-Publishing + command: | + export NPM_ID_TOKEN=$(circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}') + make release-pre + - failed-release-notification + + npm-validation: + parameters: + executor: + type: string + executor: << parameters.executor >> + steps: + - prepare-workspace + - run: + name: Validating NPM artifacts + command: bash ./release-scripts/validate-npm-artifacts.sh + - failed-release-notification + + test-release: + parameters: + executor: + type: string + cli_download_base_url: + type: string + default: << pipeline.parameters.cli_download_base_url >> + setup_steps: + type: steps + default: [] + executor: << parameters.executor >> + steps: + - steps: << parameters.setup_steps >> + - prepare-workspace + - when: + condition: + matches: + pattern: '^macos.*' + value: << parameters.executor >> + steps: + - run: brew update && HOMEBREW_NO_ASK=1 brew install coreutils curl python3 + - when: + condition: + matches: + pattern: '^alpine' + value: << parameters.executor >> + steps: + - run: apk add python3 py3-pip bash + - when: + condition: + matches: + pattern: '^linux.*' + value: << parameters.executor >> + steps: + - run: | + export DEBIAN_FRONTEND=noninteractive + ln -fs /usr/share/zoneinfo/UTC /etc/localtime + apt update && apt install -y sudo curl python3 python3-pip python3-requests + + - run: + name: Checking Snyk CLI + shell: bash + environment: + SNYK_DISABLE_ANALYTICS: 1 + command: | + PIP_BREAK_SYSTEM_PACKAGES=1 pip install --user --upgrade requests || PIP_BREAK_SYSTEM_PACKAGES=1 pip3 install --user --upgrade requests + python scripts/install-snyk.py --base_url=<< parameters.cli_download_base_url >> $(cat binary-releases/version) || python3 scripts/install-snyk.py --base_url=<< parameters.cli_download_base_url >> $(cat binary-releases/version) + SNYK_TOKEN=${TEST_SNYK_TOKEN} ./snyk whoami --experimental + SNYK_TOKEN=${TEST_SNYK_TOKEN} ./snyk woof + + test-release-static: + parameters: + cli_download_base_url: + type: string + default: << pipeline.parameters.experimental_cli_download_base_url >> + executor: linux-machine-amd64 + steps: + - prepare-workspace + - run: + name: Build scratch test image + command: | + VERSION=$(cat binary-releases/version) + docker build \ + --build-arg CLI_DOWNLOAD_BASE_URL="<< parameters.cli_download_base_url >>" \ + --build-arg SNYK_VERSION="${VERSION}" \ + -f .circleci/Dockerfile.scratch-e2e \ + -t snyk-scratch-test . + - run: + name: Test Snyk CLI in scratch container + command: | + docker run --rm \ + -e SNYK_TOKEN="${TEST_SNYK_TOKEN}" \ + -e SNYK_DISABLE_ANALYTICS=1 \ + snyk-scratch-test \ + -c "/usr/local/bin/snyk whoami --experimental && /usr/local/bin/snyk woof" + + release-s3: + parameters: + deployment: + type: string + default: stable + executor: docker-amd64 + steps: + - prepare-workspace + - shall-deploy: + deployment: << parameters.deployment >> + - aws-cli/install: + version: << pipeline.parameters.aws_version >> + - run: + name: Publish to S3 ( << parameters.deployment >> ) + command: ./release-scripts/upload-artifacts.sh << parameters.deployment >> + - failed-release-notification + + release-github: + executor: docker-amd64 + steps: + - prepare-workspace + - shall-deploy: + deployment: stable + - gh/setup: + token: HAMMERHEAD_GITHUB_PAT + version: << pipeline.parameters.gh_version >> + - run: + name: Publish to GitHub + command: ./release-scripts/upload-artifacts.sh github + - run: + name: Create Jira Release + command: ./release-scripts/create-jira-release.sh + - failed-release-notification + + release-npm: + parameters: + deployment: + type: string + default: stable + executor: docker-amd64 + steps: + - prepare-workspace + - shall-deploy: + deployment: << parameters.deployment >> + - run: + name: Publish to npm ( << parameters.deployment >> ) + command: | + export NPM_ID_TOKEN=$(circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}') + ./release-scripts/upload-artifacts.sh npm + - failed-release-notification + + trigger-building-distribution-channels: + parameters: + deployment: + type: string + default: stable + executor: docker-amd64 + steps: + - prepare-workspace + - shall-deploy: + deployment: << parameters.deployment >> + - run: + name: Trigger build-and-publish workflow at snyk-images + command: ./release-scripts/upload-artifacts.sh trigger-distribution-channels + - failed-release-notification + + trigger-build-agentic-integration: + executor: docker-amd64 + steps: + - prepare-workspace + - run: + name: Trigger build-and-release workflow at agentic-integration-wrappers + command: ./release-scripts/upload-artifacts.sh trigger_build_agentic_integration + - failed-release-notification + + noop: + executor: generic-ubuntu + steps: + - run: + name: No operation + command: echo Nothing to be done! diff --git a/.circleci/continue_config_light.yml b/.circleci/continue_config_light.yml new file mode 100644 index 0000000000..eafde30433 --- /dev/null +++ b/.circleci/continue_config_light.yml @@ -0,0 +1,14 @@ +version: 2.1 + +# Lightweight continuation for non-code PRs (CLI-1625). +orbs: + prodsec: snyk/prodsec-orb@1 + +workflows: + test_and_release: + jobs: + - prodsec/secrets-scan: + name: secrets-scan + context: snyk-bot-slack + channel: cli-alerts + trusted-branch: main diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 08919bfea0..ffb9a4bd87 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -420,6 +420,38 @@ Your PR checks will run every time you push changes to your branch. The [test pipeline](https://app.circleci.com/pipelines/github/snyk/cli?filter=mine) is on CircleCI. This is where your changes are built and tested. +A short **setup** job runs first. It compares your branch to `main` and continues one of two configs: + +| Path | When | `test_and_release` runs | +| ---- | ---- | ----------------------- | +| **Full** | Any changed file matches a [code path](#what-triggers-the-full-pipeline) | Builds, unit tests, acceptance tests, and the rest of the existing pipeline | +| **Lightweight** | Only non-code files changed | `secrets-scan` only | + +Mixed PRs (for example `.md` and `.ts`) always take the **full** path. + +**Branches named `docs/*`** use the same full vs lightweight rules. Md-only `docs/*` PRs are lightweight +(`secrets-scan` only), not a separate pipeline. + +`docs-only-check` (full config, `docs/*` only) allows `.md`, `.svg`, and `.jpg`—see +[`scripts/ci/is-docs-only-changes.sh`](scripts/ci/is-docs-only-changes.sh). It runs only when the full +config is selected, not on typical md-only PRs. Repo help assets: `help/ide.svg`, `help/monitor.svg`; +`help/snyk-cli-screenshot.png` is not in that allowlist. + +#### What triggers the full pipeline + +If **any** changed file (vs merge-base with `main`, excluding `node_modules/`) matches one of these, you get the full +pipeline: + +- Source: `*.go`, `*.ts`, `*.js`, `*.sh` +- Build / deps: `Makefile`, `go.mod`, `go.sum`, `package.json`, `package-lock.json` +- Tooling: `.circleci/**` (except `continue_config_light.yml`), `.nvmrc` + +Changes only to other files — for example `.md`, `.yaml`/`.yml` (outside `.circleci/`), `CODEOWNERS`, or +`.github/workflows/**` — use the lightweight path. + +The authoritative list lives in [`scripts/ci/code-change-pathspecs.txt`](scripts/ci/code-change-pathspecs.txt) (used by +[`scripts/ci/has-code-changes.sh`](scripts/ci/has-code-changes.sh)). + If any checks fail, fix them and force push your changes again. Make sure to review and tidy up your branch so that it remains easy to follow. diff --git a/cliv2/internal/persona/agent/agent.go b/cliv2/internal/persona/agent/agent.go index ce82a235ad..b9551e0876 100644 --- a/cliv2/internal/persona/agent/agent.go +++ b/cliv2/internal/persona/agent/agent.go @@ -126,10 +126,8 @@ func detectAgent(l lookup) (Agent, bool) { // canonicalAgent normalises an explicitly declared AI_AGENT value onto the set // of canonical agent names. func canonicalAgent(name string) Agent { - switch Agent(name) { - case "github-copilot-cli": + if Agent(name) == "github-copilot-cli" { return AgentGitHubCopilot - default: - return Agent(name) } + return Agent(name) } diff --git a/cliv2/internal/persona/interactive/interactive_test.go b/cliv2/internal/persona/interactive/interactive_test.go index 04a01c9f08..3efcf076f6 100644 --- a/cliv2/internal/persona/interactive/interactive_test.go +++ b/cliv2/internal/persona/interactive/interactive_test.go @@ -66,8 +66,12 @@ func Test_InteractiveMode_Has(t *testing.T) { func Test_isTerminal_pipeIsNotATerminal(t *testing.T) { r, w, err := os.Pipe() require.NoError(t, err) - defer r.Close() - defer w.Close() + defer func(r *os.File) { + _ = r.Close() + }(r) + defer func(w *os.File) { + _ = w.Close() + }(w) assert.False(t, isTerminal(r), "read end of a pipe is not a terminal") assert.False(t, isTerminal(w), "write end of a pipe is not a terminal") @@ -76,7 +80,9 @@ func Test_isTerminal_pipeIsNotATerminal(t *testing.T) { func Test_isTerminal_regularFileIsNotATerminal(t *testing.T) { f, err := os.CreateTemp(t.TempDir(), "interactive-test") require.NoError(t, err) - defer f.Close() + defer func(f *os.File) { + _ = f.Close() + }(f) assert.False(t, isTerminal(f), "a regular file is not a terminal") } diff --git a/scripts/ci/code-change-pathspecs.txt b/scripts/ci/code-change-pathspecs.txt new file mode 100644 index 0000000000..b5a1c70e3f --- /dev/null +++ b/scripts/ci/code-change-pathspecs.txt @@ -0,0 +1,16 @@ +# Git pathspecs that require the full CI pipeline (one per line). +# Used by: scripts/ci/has-code-changes.sh +# Slice 3 setup job should call has-code-changes.sh (not duplicate regex in path-filtering orb). +*.go +*.ts +*.js +*.sh +:(glob)**/Makefile +:(glob)**/go.mod +:(glob)**/go.sum +:(glob)**/package.json +:(glob)**/package-lock.json +.circleci/ +:(exclude,glob).circleci/continue_config_light.yml +.nvmrc +:(exclude,glob)**/node_modules/** diff --git a/scripts/ci/continue-pipeline.sh b/scripts/ci/continue-pipeline.sh new file mode 100755 index 0000000000..0adae91981 --- /dev/null +++ b/scripts/ci/continue-pipeline.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# POST a continuation config to the CircleCI dynamic configuration API. +set -euo pipefail + +CONFIG_PATH="${1:-}" +if [ -z "$CONFIG_PATH" ] && [ -r /tmp/continuation-config-path.txt ]; then + CONFIG_PATH="$(cat /tmp/continuation-config-path.txt)" +fi + +if [ -z "$CONFIG_PATH" ] || [ ! -r "$CONFIG_PATH" ]; then + echo "continue-pipeline: missing or unreadable config path" >&2 + exit 2 +fi + +if [ -z "${CIRCLE_CONTINUATION_KEY:-}" ]; then + echo "continue-pipeline: CIRCLE_CONTINUATION_KEY is required" >&2 + exit 1 +fi + +mkdir -p /tmp/circleci +jq -Rs '.' "$CONFIG_PATH" > /tmp/circleci/config-string.json +jq -n \ + --arg continuation "$CIRCLE_CONTINUATION_KEY" \ + --slurpfile config /tmp/circleci/config-string.json \ + '{"continuation-key": $continuation, "configuration": $config|join("\n"), "parameters": {}}' \ + > /tmp/circleci/continue_post.json +code="$(curl -sS -o /tmp/circleci/continue_response.json -w '%{http_code}' \ + -X POST \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + --data @/tmp/circleci/continue_post.json \ + "https://${CIRCLECI_DOMAIN:-circleci.com}/api/v2/pipeline/continue")" +cat /tmp/circleci/continue_response.json +[ "$code" = "200" ] diff --git a/scripts/ci/has-code-changes.sh b/scripts/ci/has-code-changes.sh new file mode 100755 index 0000000000..dd1e549215 --- /dev/null +++ b/scripts/ci/has-code-changes.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Exit 0 if git diff vs merge-base includes any code-change pathspec; else exit 1. +set -euo pipefail + +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +PATHSPECS_FILE="${CODE_CHANGE_PATHSPECS_FILE:-$SCRIPT_DIR/code-change-pathspecs.txt}" +BASE_REF="${BASE_REF:-origin/main}" + +if [ ! -r "$PATHSPECS_FILE" ]; then + echo "has-code-changes: missing pathspecs file: $PATHSPECS_FILE" >&2 + exit 2 +fi + +PATHSPECS=() +while IFS= read -r line; do + PATHSPECS+=("$line") +done < <(grep -v '^[[:space:]]*#' "$PATHSPECS_FILE" | grep -v '^[[:space:]]*$' || true) +if [ "${#PATHSPECS[@]}" -eq 0 ]; then + echo "has-code-changes: no pathspecs in $PATHSPECS_FILE" >&2 + exit 2 +fi + +if ! git rev-parse --verify "$BASE_REF" >/dev/null 2>&1; then + echo "has-code-changes: unknown base ref: $BASE_REF" >&2 + exit 2 +fi + +MERGE_BASE="$(git merge-base HEAD "$BASE_REF")" +if [ -n "$(git diff --name-only "${MERGE_BASE}...HEAD" -- "${PATHSPECS[@]}")" ]; then + exit 0 +fi +exit 1 diff --git a/scripts/ci/is-docs-only-changes.sh b/scripts/ci/is-docs-only-changes.sh new file mode 100755 index 0000000000..f7386b506b --- /dev/null +++ b/scripts/ci/is-docs-only-changes.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Exit 0 if all changed files are docs assets (.md, .svg, .jpg); else exit 1. +set -euo pipefail + +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +ALLOWED='(\.md|\.svg|\.jpg)$' + +CHANGED_FILES="$("$SCRIPT_DIR/list-changed-files.sh")" +if [ -z "$CHANGED_FILES" ]; then + exit 0 +fi + +while IFS= read -r file; do + [ -z "$file" ] && continue + if echo "$file" | grep -qE '(^|/)node_modules/'; then + continue + fi + if ! echo "$file" | grep -qE "$ALLOWED"; then + echo "Error: disallowed file type for docs-only branch: $file" >&2 + exit 1 + fi +done <<< "$CHANGED_FILES" + +exit 0 diff --git a/scripts/ci/list-changed-files.sh b/scripts/ci/list-changed-files.sh new file mode 100755 index 0000000000..0c8047c0af --- /dev/null +++ b/scripts/ci/list-changed-files.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# List files changed on HEAD since merge-base with a base ref (default origin/main). +set -euo pipefail + +BASE_REF="${1:-${BASE_REF:-origin/main}}" + +if ! git rev-parse --verify "$BASE_REF" >/dev/null 2>&1; then + echo "list-changed-files: unknown base ref: $BASE_REF" >&2 + exit 2 +fi + +MERGE_BASE="$(git merge-base HEAD "$BASE_REF")" +git diff --name-only "${MERGE_BASE}...HEAD" diff --git a/scripts/ci/test_has_code_changes.sh b/scripts/ci/test_has_code_changes.sh new file mode 100755 index 0000000000..2d9f198cbd --- /dev/null +++ b/scripts/ci/test_has_code_changes.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +HAS_CODE="$SCRIPT_DIR/has-code-changes.sh" + +# ponytail: temp repo exercises real git diff + pathspecs (no hand-rolled pattern matcher). +with_repo() { + local dir + dir=$(mktemp -d) + trap 'rm -rf "$dir"' RETURN + + cp "$SCRIPT_DIR/has-code-changes.sh" "$SCRIPT_DIR/list-changed-files.sh" "$dir/" + chmod +x "$dir"/*.sh + + cd "$dir" + git init -q + git config user.email 'ci-test@example.com' + git config user.name 'ci-test' + echo base >README.md + git add . && git commit -qm base + + export BASE_REF=HEAD + export CODE_CHANGE_PATHSPECS_FILE="$SCRIPT_DIR/code-change-pathspecs.txt" + "$@" +} + +commit_paths() { + for f in "$@"; do + mkdir -p "$(dirname -- "$f")" + touch "$f" + git add -- "$f" + done + git commit -qm "add: $*" +} + +assert_no() { + commit_paths "$@" + if BASE_REF=HEAD~1 "$HAS_CODE"; then + echo "FAIL: expected no code match for: $*" >&2 + exit 1 + fi + echo "ok (no code): $*" + git reset --hard HEAD~1 >/dev/null +} + +assert_yes() { + commit_paths "$@" + if ! BASE_REF=HEAD~1 "$HAS_CODE"; then + echo "FAIL: expected code match for: $*" >&2 + exit 1 + fi + echo "ok (code): $*" + git reset --hard HEAD~1 >/dev/null +} + +with_repo assert_no CONTRIBUTING.md .github/CODEOWNERS +with_repo assert_no README.md docs/guide.md +with_repo assert_no test/fixtures/pnpm-app/node_modules/.pnpm/foo/index.mjs +with_repo assert_no .circleci/continue_config_light.yml + +with_repo assert_yes src/cli/main.ts +with_repo assert_yes cliv2/pkg/foo/bar.go +with_repo assert_yes scripts/install-dev-dependencies.sh +with_repo assert_yes Makefile +with_repo assert_yes cliv2/Makefile +with_repo assert_yes cliv2/go.mod +with_repo assert_yes cliv2/go.sum +with_repo assert_yes package.json +with_repo assert_yes packages/foo/package-lock.json +with_repo assert_yes .circleci/config.yml +with_repo assert_yes .circleci/continue_config.yml +with_repo assert_yes .nvmrc +with_repo assert_yes dangerfile.js +with_repo assert_yes CONTRIBUTING.md src/foo.ts + +echo "test_has_code_changes: all passed" diff --git a/scripts/ci/test_is_docs_only_changes.sh b/scripts/ci/test_is_docs_only_changes.sh new file mode 100755 index 0000000000..08b0d77dfa --- /dev/null +++ b/scripts/ci/test_is_docs_only_changes.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +IS_DOCS="$SCRIPT_DIR/is-docs-only-changes.sh" + +with_repo() { + local dir + dir=$(mktemp -d) + trap 'rm -rf "$dir"' RETURN + + cp "$SCRIPT_DIR/is-docs-only-changes.sh" "$SCRIPT_DIR/list-changed-files.sh" "$dir/" + chmod +x "$dir"/*.sh + + cd "$dir" + git init -q + git config user.email 'ci-test@example.com' + git config user.name 'ci-test' + echo base >README.md + git add . && git commit -qm base + "$@" +} + +commit_paths() { + for f in "$@"; do + mkdir -p "$(dirname -- "$f")" + touch "$f" + git add -- "$f" + done + git commit -qm "add: $*" +} + +assert_docs() { + commit_paths "$@" + if ! BASE_REF=HEAD~1 "$IS_DOCS"; then + echo "FAIL: expected docs-only for: $*" >&2 + exit 1 + fi + echo "ok (docs): $*" + git reset --hard HEAD~1 >/dev/null +} + +assert_not_docs() { + commit_paths "$@" + if BASE_REF=HEAD~1 "$IS_DOCS"; then + echo "FAIL: expected non-docs failure for: $*" >&2 + exit 1 + fi + echo "ok (not docs): $*" + git reset --hard HEAD~1 >/dev/null +} + +with_repo assert_docs README.md docs/guide.md +with_repo assert_docs assets/logo.svg +with_repo assert_not_docs README.md src/foo.ts +with_repo assert_not_docs CODEOWNERS + +echo "test_is_docs_only_changes: all passed"