From c7fa431316c2d43740545785c28c42f30fbc3cb0 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Tue, 28 Oct 2025 15:11:56 +0200 Subject: [PATCH 01/28] created new release using workflows and deleted old one --- .github/workflows/release.yml | 171 ++++++++++++++++++++++++++++ release/buildAndUpload.sh | 73 ------------ release/pipelines.yml | 89 --------------- release/specs/frogbot-rbc-spec.json | 8 -- 4 files changed, 171 insertions(+), 170 deletions(-) create mode 100644 .github/workflows/release.yml delete mode 100755 release/buildAndUpload.sh delete mode 100644 release/pipelines.yml delete mode 100644 release/specs/frogbot-rbc-spec.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..72c20b4a9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,171 @@ +name: Release Frogbot + +on: + release: + types: [published] + +# Required permissions +permissions: + contents: write + actions: read + +jobs: + release: + name: Release Frogbot v3 + runs-on: frogbot-release + + # Only run for v3.x.x releases + if: startsWith(github.event.release.tag_name, 'v3.') + + steps: + - name: Extract version from tag + id: version + run: | + TAG="${{ github.event.release.tag_name }}" + VERSION="${TAG#v}" + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag=$TAG" >> $GITHUB_OUTPUT + echo "Release version: $VERSION" + + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.release.tag_name }} + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + cache: true + + - name: Download JFrog CLI + run: | + curl -fL https://install-cli.jfrog.io | sh + chmod +x jf + sudo mv jf /usr/local/bin/ + + - name: Configure JFrog CLI + env: + JF_URL: ${{ secrets.JF_URL }} + JF_USER: ${{ secrets.JF_USER }} + JF_PASSWORD: ${{ secrets.JF_PASSWORD }} + run: | + jf c rm --quiet || true + jf c add internal --url="$JF_URL" --user="$JF_USER" --password="$JF_PASSWORD" + jf goc --repo-resolve ecosys-go-virtual + + - name: Generate mocks + run: go generate ./... + + - name: Run JFrog Audit (blocking) + run: jf audit --fail=true + + - name: Set up Node.js for Action + uses: actions/setup-node@v4 + with: + node-version: '16' + cache: 'npm' + cache-dependency-path: action/package-lock.json + + - name: Build GitHub Action + working-directory: action + run: | + npm ci --ignore-scripts + npm run compile + npm run format-check + npm test + + - name: Commit and update tag with compiled action + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add action/lib/ + + # Only commit and update tag if there are changes + if ! git diff --staged --quiet; then + echo "Action files changed, updating tag..." + git commit -m "Build action for ${{ steps.version.outputs.tag }}" + + # Update the release tag to point to the new commit + git tag -f ${{ steps.version.outputs.tag }} + git push origin ${{ steps.version.outputs.tag }} --force + + echo "Tag updated with compiled action" + else + echo "No changes to action files" + fi + + - name: Update GitHub Action major version tag (v3) + run: | + # Update v3 tag to point to the latest v3.x.x release + git tag -f v3 + git push origin v3 --force + echo "Updated v3 tag to ${{ steps.version.outputs.tag }}" + + - name: Build and upload binaries + env: + VERSION: ${{ steps.version.outputs.tag }} + JFROG_CLI_BUILD_NAME: ecosystem-frogbot-release + JFROG_CLI_BUILD_NUMBER: ${{ github.run_number }} + JFROG_CLI_BUILD_PROJECT: ecosys + run: | + env -i PATH=$PATH HOME=$HOME \ + JFROG_CLI_BUILD_NAME=$JFROG_CLI_BUILD_NAME \ + JFROG_CLI_BUILD_NUMBER=$JFROG_CLI_BUILD_NUMBER \ + JFROG_CLI_BUILD_PROJECT=$JFROG_CLI_BUILD_PROJECT \ + release/buildAndUpload.sh "${{ steps.version.outputs.version }}" + + - name: Publish build info + env: + JFROG_CLI_BUILD_NAME: ecosystem-frogbot-release + JFROG_CLI_BUILD_NUMBER: ${{ github.run_number }} + JFROG_CLI_BUILD_PROJECT: ecosys + run: | + jf rt bag + jf rt bce + jf rt bp + + - name: Create and distribute release bundle + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + jf ds rbc ecosystem-frogbot $VERSION \ + --spec="release/specs/frogbot-rbc-spec.json" \ + --spec-vars="VERSION=$VERSION" \ + --sign + jf ds rbd ecosystem-frogbot $VERSION \ + --site="releases.jfrog.io" \ + --sync + + - name: Cleanup JFrog config + if: always() + run: jf c rm --quiet || true + + # On failure: delete release and tag + - name: Delete release on failure + if: failure() + uses: actions/github-script@v7 + with: + script: | + const release_id = context.payload.release.id; + const tag = context.payload.release.tag_name; + + console.log(`Deleting release ${release_id} and tag ${tag}`); + + // Delete the release + await github.rest.repos.deleteRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release_id + }); + + // Delete the tag + await github.rest.git.deleteRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `tags/${tag}` + }); + + console.log('Release and tag deleted successfully'); + diff --git a/release/buildAndUpload.sh b/release/buildAndUpload.sh deleted file mode 100755 index 8f671fe7a..000000000 --- a/release/buildAndUpload.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -set -eu - -#function build(pkg, goos, goarch, exeName) -build () { - pkg="$1" - export GOOS="$2" - export GOARCH="$3" - exeName="$4" - echo "Building $exeName for $GOOS-$GOARCH ..." - - CGO_ENABLED=0 jf go build -o "$exeName" -ldflags '-w -extldflags "-static" -X github.com/jfrog/frogbot/v2/utils.FrogbotVersion='"$version" - chmod +x "$exeName" - - # Run verification after building plugin for the correct platform of this image. - if [[ "$pkg" = "frogbot-linux-386" ]]; then - verifyVersionMatching - fi -} - -#function buildAndUpload(pkg, goos, goarch, fileExtension) -buildAndUpload () { - pkg="$1" - goos="$2" - goarch="$3" - fileExtension="$4" - exeName="frogbot$fileExtension" - - build "$pkg" "$goos" "$goarch" "$exeName" - - destPath="$pkgPath/$version/$pkg/$exeName" - echo "Uploading $exeName to $destPath ..." - jf rt u "./$exeName" "$destPath" -} - -# Verify version provided in pipelines UI matches version in frogbot source code. -verifyVersionMatching () { - echo "Verifying provided version matches built version..." - res=$(eval "./frogbot -v") - exitCode=$? - if [[ $exitCode -ne 0 ]]; then - echo "Error: Failed verifying version matches" - exit $exitCode - fi - - # Get the version which is after the last space. (expected output to -v for example: "Frogbot version version v2.0.0") - echo "Output: $res" - builtVersion="${res##* }" - # Compare versions - if [[ "$builtVersion" != "$version" ]]; then - echo "Versions dont match. Provided: $version, Actual: $builtVersion" - exit 1 - fi - echo "Versions match." -} - -version="$1" -pkgPath="ecosys-frogbot/v2" - -# Build and upload for every architecture. -# Keep 'linux-386' first to prevent unnecessary uploads in case the built version doesn't match the provided one. -buildAndUpload 'frogbot-linux-386' 'linux' '386' '' -buildAndUpload 'frogbot-linux-amd64' 'linux' 'amd64' '' -buildAndUpload 'frogbot-linux-s390x' 'linux' 's390x' '' -buildAndUpload 'frogbot-linux-arm64' 'linux' 'arm64' '' -buildAndUpload 'frogbot-linux-arm' 'linux' 'arm' '' -buildAndUpload 'frogbot-linux-ppc64' 'linux' 'ppc64' '' -buildAndUpload 'frogbot-linux-ppc64le' 'linux' 'ppc64le' '' -buildAndUpload 'frogbot-mac-386' 'darwin' 'amd64' '' -buildAndUpload 'frogbot-mac-arm64' 'darwin' 'arm64' '' -buildAndUpload 'frogbot-windows-amd64' 'windows' 'amd64' '.exe' - -jf rt u "./buildscripts/getFrogbot.sh" "$pkgPath/$version/" --flat diff --git a/release/pipelines.yml b/release/pipelines.yml deleted file mode 100644 index c7618a1dd..000000000 --- a/release/pipelines.yml +++ /dev/null @@ -1,89 +0,0 @@ -resources: - - name: frogbotGit - type: GitRepo - configuration: - path: jfrog/frogbot - branches: - include: dev - gitProvider: il_automation - -pipelines: - - name: release_frogbot - configuration: - runtime: - type: image - image: - custom: - name: releases-docker.jfrog.io/jfrog-ecosystem-integration-env - tag: latest - environmentVariables: - readOnly: - NEXT_VERSION: 0.0.0 - - steps: - - name: Release - type: Bash - configuration: - inputResources: - - name: frogbotGit - trigger: false - integrations: - - name: il_automation - - name: ecosys_entplus_deployer - execution: - onExecute: - - cd $res_frogbotGit_resourcePath - - # Set env - - export CI=true - - export JFROG_CLI_BUILD_NAME=ecosystem-frogbotGit-release - - export JFROG_CLI_BUILD_NUMBER=$run_number - - export JFROG_CLI_BUILD_PROJECT=ecosys - - # Make sure version provided - - echo "Checking variables" - - test -n "$NEXT_VERSION" -a "$NEXT_VERSION" != "0.0.0" - - # Configure Git and merge from the dev - - git checkout master - - git remote set-url origin https://$int_il_automation_token@github.com/jfrog/frogbot.git - - git merge origin/dev - - git tag v${NEXT_VERSION} - - # Download JFrog CLI - - curl -fL https://install-cli.jfrog.io | sh - - jf c rm --quiet - - jf c add internal --url=$int_ecosys_entplus_deployer_url --user=$int_ecosys_entplus_deployer_user --password=$int_ecosys_entplus_deployer_apikey - - jf goc --repo-resolve ecosys-go-virtual - - # Generate mocks - - go generate ./... - - # Audit - - jf audit --fail=false - - # Build and upload - - > - env -i PATH=$PATH HOME=$HOME - JFROG_CLI_BUILD_NAME=$JFROG_CLI_BUILD_NAME - JFROG_CLI_BUILD_NUMBER=$JFROG_CLI_BUILD_NUMBER - JFROG_CLI_BUILD_PROJECT=$JFROG_CLI_BUILD_PROJECT - release/buildAndUpload.sh "$NEXT_VERSION" - - jf rt bag && jf rt bce - - jf rt bp - - # Distribute release bundle - - jf ds rbc ecosystem-frogbot $NEXT_VERSION --spec="release/specs/frogbot-rbc-spec.json" --spec-vars="VERSION=$NEXT_VERSION" --sign - - jf ds rbd ecosystem-frogbot $NEXT_VERSION --site="releases.jfrog.io" --sync - - # Push to master - - git clean -fd - - git push - - git push --tags - - # Merge changes to dev - - git checkout dev - - git merge origin/master - - git push - onComplete: - - jf c rm --quiet diff --git a/release/specs/frogbot-rbc-spec.json b/release/specs/frogbot-rbc-spec.json deleted file mode 100644 index ea24a35cd..000000000 --- a/release/specs/frogbot-rbc-spec.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "files": [ - { - "pattern": "ecosys-frogbot/(v2/${VERSION}/*)", - "target": "frogbot/{1}" - } - ] -} From a748238327c3d7888773fd9ffd0633abad311640 Mon Sep 17 00:00:00 2001 From: Eran Turgeman <81029514+eranturgeman@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:34:21 +0200 Subject: [PATCH 02/28] Fix Frogbot Scan-pr broken tests (#944) --- scanpullrequest/scanallpullrequests_test.go | 3 +- scanpullrequest/scanpullrequest_test.go | 12 +++---- .../test_proj_pip_with_vulnerability.md | 31 +++++++++++-------- .../expected_response_multi_dir.md | 30 ++++++++++-------- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/scanpullrequest/scanallpullrequests_test.go b/scanpullrequest/scanallpullrequests_test.go index 9fb31d07d..bd5410136 100644 --- a/scanpullrequest/scanallpullrequests_test.go +++ b/scanpullrequest/scanallpullrequests_test.go @@ -3,11 +3,12 @@ package scanpullrequest import ( "context" "fmt" - "github.com/jfrog/jfrog-cli-security/utils/xsc" "path/filepath" "testing" "time" + "github.com/jfrog/jfrog-cli-security/utils/xsc" + "github.com/golang/mock/gomock" biutils "github.com/jfrog/build-info-go/utils" "github.com/jfrog/frogbot/v2/testdata" diff --git a/scanpullrequest/scanpullrequest_test.go b/scanpullrequest/scanpullrequest_test.go index 5fdb46cab..0f99261c4 100644 --- a/scanpullrequest/scanpullrequest_test.go +++ b/scanpullrequest/scanpullrequest_test.go @@ -98,7 +98,7 @@ func TestScanResultsToIssuesCollection(t *testing.T) { Applicable: "Applicable", FixedVersions: []string{"1.2.3"}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 21}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 26}, ImpactedDependencyName: "Dep-1", }, Cves: []formats.CveRow{{Id: "CVE-2022-2122", Applicability: &formats.Applicability{Status: "Applicable", ScannerDescription: "rule-msg", Evidence: []formats.Evidence{{Reason: "result-msg", Location: formats.Location{File: "file1", StartLine: 1, StartColumn: 10, EndLine: 2, EndColumn: 11, Snippet: "snippet"}}}}}}, @@ -107,7 +107,7 @@ func TestScanResultsToIssuesCollection(t *testing.T) { Applicable: "Not Applicable", FixedVersions: []string{"1.2.2"}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 2}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 3}, ImpactedDependencyName: "Dep-2", }, Cves: []formats.CveRow{{Id: "CVE-2023-3122", Applicability: &formats.Applicability{Status: "Not Applicable", ScannerDescription: "rule-msg"}}}, @@ -117,7 +117,7 @@ func TestScanResultsToIssuesCollection(t *testing.T) { { SeverityDetails: formats.SeverityDetails{ Severity: "High", - SeverityNumValue: 21, + SeverityNumValue: 26, }, ScannerInfo: formats.ScannerInfo{ ScannerDescription: "rule-msg", @@ -138,7 +138,7 @@ func TestScanResultsToIssuesCollection(t *testing.T) { { SeverityDetails: formats.SeverityDetails{ Severity: "High", - SeverityNumValue: 21, + SeverityNumValue: 26, }, ScannerInfo: formats.ScannerInfo{ ScannerDescription: "rule-msg", @@ -159,7 +159,7 @@ func TestScanResultsToIssuesCollection(t *testing.T) { { SeverityDetails: formats.SeverityDetails{ Severity: "High", - SeverityNumValue: 21, + SeverityNumValue: 26, }, ScannerInfo: formats.ScannerInfo{ ScannerDescription: "rule-msg", @@ -183,7 +183,7 @@ func TestScanResultsToIssuesCollection(t *testing.T) { ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ SeverityDetails: formats.SeverityDetails{ Severity: "Medium", - SeverityNumValue: 14, + SeverityNumValue: 19, }, ImpactedDependencyName: "Dep-1", }, diff --git a/testdata/messages/integration/test_proj_pip_with_vulnerability.md b/testdata/messages/integration/test_proj_pip_with_vulnerability.md index 00779aec8..b16086630 100644 --- a/testdata/messages/integration/test_proj_pip_with_vulnerability.md +++ b/testdata/messages/integration/test_proj_pip_with_vulnerability.md @@ -11,11 +11,11 @@ ## πŸ“— Scan Summary -- Frogbot scanned for vulnerabilities and found 1 issues +- Frogbot scanned for vulnerabilities and found 2 issues | Scan Category | Status | Security Issues | | --------------------- | :-----------------------------------: | ----------------------------------- | -| **Software Composition Analysis** | βœ… Done |
1 Issues Found 1 High
| +| **Software Composition Analysis** | βœ… Done |
2 Issues Found 2 High
| | **Contextual Analysis** | βœ… Done | - | | **Static Application Security Testing (SAST)** | βœ… Done | Not Found | | **Secrets** | βœ… Done | - | @@ -28,6 +28,7 @@ | Severity | ID | Contextual Analysis | Direct Dependencies | Impacted Dependency | Fixed Versions | | :---------------------: | :-----------------------------------: | :-----------------------------------: | :-----------------------------------: | :-----------------------------------: | :-----------------------------------: | | ![high](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | CVE-2022-29217 | Not Covered | pyjwt:1.7.1 | pyjwt 1.7.1 | [2.4.0] | +| ![high (not applicable)](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableHigh.png)
High | CVE-2025-45768 | Not Applicable | pyjwt:1.7.1 | pyjwt 1.7.1 | - | @@ -35,6 +36,7 @@ ### πŸ”– Details +
[ CVE-2022-29217 ] pyjwt 1.7.1 ### Vulnerability Details | | | @@ -67,17 +69,7 @@ For example, an application might have planned to validate an `EdDSA`-signed tok # Making a good jwt token that should work by signing it with the private key encoded_good = jwt.encode({"test": 1234}, priv_key_bytes, algorithm="EdDSA") ``` -An attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - -```python -# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret -encoded_bad = jwt.encode({"test": 1234}, pub_key_bytes, algorithm="HS256") -``` - -The following vulnerable `decode` call will accept BOTH of the above tokens as valid - -``` -decoded = jwt.decode(encoded_good, pub_key_bytes, -algorithms=jwt.algorithms.get_default_algorithms()) -``` +A... **Remediation:** ##### Development mitigations @@ -87,7 +79,20 @@ For example, replace the following call - `jwt.decode(encoded_jwt, pub_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())` With - `jwt.decode(encoded_jwt, pub_key_bytes, algorithms=["ES256"])` +
+ +
[ CVE-2025-45768 ] pyjwt 1.7.1 + +### Vulnerability Details +| | | +| --------------------- | :-----------------------------------: | +| **Contextual Analysis:** | Not Applicable | +| **Direct Dependencies:** | pyjwt:1.7.1 | +| **Impacted Dependency:** | pyjwt:1.7.1 | +| **Fixed Versions:** | - | +| **CVSS V3:** | 7.0 | +pyjwt v2.10.1 was discovered to contain weak encryption. NOTE: this is disputed by the Supplier because the key length is chosen by the application that uses the library (admittedly, library users may benefit from a minimum value and a mechanism for opting in to strict enforcement).
--- diff --git a/testdata/scanpullrequest/expected_response_multi_dir.md b/testdata/scanpullrequest/expected_response_multi_dir.md index e83ab7d5d..197a8aafb 100644 --- a/testdata/scanpullrequest/expected_response_multi_dir.md +++ b/testdata/scanpullrequest/expected_response_multi_dir.md @@ -11,11 +11,11 @@ ## πŸ“— Scan Summary -- Frogbot scanned for vulnerabilities and found 2 issues +- Frogbot scanned for vulnerabilities and found 3 issues | Scan Category | Status | Security Issues | | --------------------- | :-----------------------------------: | ----------------------------------- | -| **Software Composition Analysis** | βœ… Done |
2 Issues Found 2 High
| +| **Software Composition Analysis** | βœ… Done |
3 Issues Found 3 High
| | **Contextual Analysis** | βœ… Done | - | | **Static Application Security Testing (SAST)** | βœ… Done | Not Found | | **Secrets** | βœ… Done | - | @@ -29,6 +29,7 @@ | :---------------------: | :-----------------------------------: | :-----------------------------------: | :-----------------------------------: | :-----------------------------------: | :-----------------------------------: | | ![high (not applicable)](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableHigh.png)
High | CVE-2022-3517 | Not Applicable | minimatch:3.0.4 | minimatch 3.0.4 | [3.0.5] | | ![high](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | CVE-2022-29217 | Not Covered | pyjwt:1.7.1 | pyjwt 1.7.1 | [2.4.0] | +| ![high (not applicable)](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableHigh.png)
High | CVE-2025-45768 | Not Applicable | pyjwt:1.7.1 | pyjwt 1.7.1 | - | @@ -82,17 +83,7 @@ For example, an application might have planned to validate an `EdDSA`-signed tok # Making a good jwt token that should work by signing it with the private key encoded_good = jwt.encode({"test": 1234}, priv_key_bytes, algorithm="EdDSA") ``` -An attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - -```python -# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret -encoded_bad = jwt.encode({"test": 1234}, pub_key_bytes, algorithm="HS256") -``` - -The following vulnerable `decode` call will accept BOTH of the above tokens as valid - -``` -decoded = jwt.decode(encoded_good, pub_key_bytes, -algorithms=jwt.algorithms.get_default_algorithms()) -``` +A... **Remediation:** ##### Development mitigations @@ -104,6 +95,19 @@ With - `jwt.decode(encoded_jwt, pub_key_bytes, algorithms=["ES256"])`
+
[ CVE-2025-45768 ] pyjwt 1.7.1 + +### Vulnerability Details +| | | +| --------------------- | :-----------------------------------: | +| **Contextual Analysis:** | Not Applicable | +| **Direct Dependencies:** | pyjwt:1.7.1 | +| **Impacted Dependency:** | pyjwt:1.7.1 | +| **Fixed Versions:** | - | +| **CVSS V3:** | 7.0 | + +pyjwt v2.10.1 was discovered to contain weak encryption. NOTE: this is disputed by the Supplier because the key length is chosen by the application that uses the library (admittedly, library users may benefit from a minimum value and a mechanism for opting in to strict enforcement).
+ ---
From 8777a7b222116daa77dc05ca58c35c67052a0290 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 11:49:07 +0200 Subject: [PATCH 03/28] Change release workflow to use ubuntu-latest runner --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 72c20b4a9..7ee431a62 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ permissions: jobs: release: name: Release Frogbot v3 - runs-on: frogbot-release + runs-on: ubuntu-latest # Only run for v3.x.x releases if: startsWith(github.event.release.tag_name, 'v3.') From 57dba96a4af4e1c6695a475545d84936f0525dfa Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 11:52:28 +0200 Subject: [PATCH 04/28] Restore release/buildAndUpload.sh script --- release/buildAndUpload.sh | 74 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100755 release/buildAndUpload.sh diff --git a/release/buildAndUpload.sh b/release/buildAndUpload.sh new file mode 100755 index 000000000..4b06a9703 --- /dev/null +++ b/release/buildAndUpload.sh @@ -0,0 +1,74 @@ +#!/bin/bash +set -eu + +#function build(pkg, goos, goarch, exeName) +build () { + pkg="$1" + export GOOS="$2" + export GOARCH="$3" + exeName="$4" + echo "Building $exeName for $GOOS-$GOARCH ..." + + CGO_ENABLED=0 jf go build -o "$exeName" -ldflags '-w -extldflags "-static" -X github.com/jfrog/frogbot/v2/utils.FrogbotVersion='"$version" + chmod +x "$exeName" + + # Run verification after building plugin for the correct platform of this image. + if [[ "$pkg" = "frogbot-linux-386" ]]; then + verifyVersionMatching + fi +} + +#function buildAndUpload(pkg, goos, goarch, fileExtension) +buildAndUpload () { + pkg="$1" + goos="$2" + goarch="$3" + fileExtension="$4" + exeName="frogbot$fileExtension" + + build "$pkg" "$goos" "$goarch" "$exeName" + + destPath="$pkgPath/$version/$pkg/$exeName" + echo "Uploading $exeName to $destPath ..." + jf rt u "./$exeName" "$destPath" +} + +# Verify version provided in pipelines UI matches version in frogbot source code. +verifyVersionMatching () { + echo "Verifying provided version matches built version..." + res=$(eval "./frogbot -v") + exitCode=$? + if [[ $exitCode -ne 0 ]]; then + echo "Error: Failed verifying version matches" + exit $exitCode + fi + + # Get the version which is after the last space. (expected output to -v for example: "Frogbot version version v2.0.0") + echo "Output: $res" + builtVersion="${res##* }" + # Compare versions + if [[ "$builtVersion" != "$version" ]]; then + echo "Versions dont match. Provided: $version, Actual: $builtVersion" + exit 1 + fi + echo "Versions match." +} + +version="$1" +pkgPath="ecosys-frogbot/v2" + +# Build and upload for every architecture. +# Keep 'linux-386' first to prevent unnecessary uploads in case the built version doesn't match the provided one. +buildAndUpload 'frogbot-linux-386' 'linux' '386' '' +buildAndUpload 'frogbot-linux-amd64' 'linux' 'amd64' '' +buildAndUpload 'frogbot-linux-s390x' 'linux' 's390x' '' +buildAndUpload 'frogbot-linux-arm64' 'linux' 'arm64' '' +buildAndUpload 'frogbot-linux-arm' 'linux' 'arm' '' +buildAndUpload 'frogbot-linux-ppc64' 'linux' 'ppc64' '' +buildAndUpload 'frogbot-linux-ppc64le' 'linux' 'ppc64le' '' +buildAndUpload 'frogbot-mac-386' 'darwin' 'amd64' '' +buildAndUpload 'frogbot-mac-arm64' 'darwin' 'arm64' '' +buildAndUpload 'frogbot-windows-amd64' 'windows' 'amd64' '.exe' + +jf rt u "./buildscripts/getFrogbot.sh" "$pkgPath/$version/" --flat + From 254b518cc90ef7ab6266638ad93b74d5e0f4379c Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 13:41:40 +0200 Subject: [PATCH 05/28] gave frogbot the needed thread count to run in parallel (#942) --- utils/consts.go | 3 +++ utils/scandetails.go | 1 + 2 files changed, 4 insertions(+) diff --git a/utils/consts.go b/utils/consts.go index 6c483a843..78fbc7b2c 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -11,6 +11,9 @@ const ( // Errors errUnsupportedMultiRepo = "multi repository configuration isn't supported. Only one repository configuration is allowed" + // MaxConcurrentScanners represents the maximum number of threads for running JFrog CLI scanners concurrently + MaxConcurrentScanners = 5 + // VCS providers params GitHub vcsProvider = "github" GitLab vcsProvider = "gitlab" diff --git a/utils/scandetails.go b/utils/scandetails.go index 291410085..2ae9cc408 100644 --- a/utils/scandetails.go +++ b/utils/scandetails.go @@ -182,6 +182,7 @@ func (sc *ScanDetails) RunInstallAndAudit(workDirs ...string) (auditResults *res SetDiffMode(sc.diffScan). SetResultsToCompare(sc.ResultsToCompare). SetMultiScanId(sc.MultiScanId). + SetThreads(MaxConcurrentScanners). SetStartTime(sc.StartTime) return audit.RunAudit(auditParams) From 3a8e8fead4a2c3d4adb2828a32869a286217ea69 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 13:48:35 +0200 Subject: [PATCH 06/28] Fix JFrog CLI installation - remove redundant chmod and mv --- .github/workflows/release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7ee431a62..263622e34 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,8 +42,7 @@ jobs: - name: Download JFrog CLI run: | curl -fL https://install-cli.jfrog.io | sh - chmod +x jf - sudo mv jf /usr/local/bin/ + # The install script already moves jf to /usr/local/bin/ - name: Configure JFrog CLI env: From 82910932b0ba509eff709e7db57ae76a5abca0d3 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 13:58:00 +0200 Subject: [PATCH 07/28] Use JF_ACCESS_TOKEN instead of JF_USER and JF_PASSWORD --- .github/workflows/release.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 263622e34..521b79e57 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,11 +47,10 @@ jobs: - name: Configure JFrog CLI env: JF_URL: ${{ secrets.JF_URL }} - JF_USER: ${{ secrets.JF_USER }} - JF_PASSWORD: ${{ secrets.JF_PASSWORD }} + JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }} run: | jf c rm --quiet || true - jf c add internal --url="$JF_URL" --user="$JF_USER" --password="$JF_PASSWORD" + jf c add internal --url="$JF_URL" --access-token="$JF_ACCESS_TOKEN" jf goc --repo-resolve ecosys-go-virtual - name: Generate mocks From 0585d57dbd21d50c62a936edf531686258dbfd9d Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 14:01:47 +0200 Subject: [PATCH 08/28] Add JF_URL and JF_ACCESS_TOKEN env vars to audit step for proper authentication --- .github/workflows/release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 521b79e57..119a64160 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -57,6 +57,9 @@ jobs: run: go generate ./... - name: Run JFrog Audit (blocking) + env: + JF_URL: ${{ secrets.JF_URL }} + JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }} run: jf audit --fail=true - name: Set up Node.js for Action @@ -112,6 +115,7 @@ jobs: JFROG_CLI_BUILD_NAME=$JFROG_CLI_BUILD_NAME \ JFROG_CLI_BUILD_NUMBER=$JFROG_CLI_BUILD_NUMBER \ JFROG_CLI_BUILD_PROJECT=$JFROG_CLI_BUILD_PROJECT \ + CI=true \ release/buildAndUpload.sh "${{ steps.version.outputs.version }}" - name: Publish build info From 6cb6e1cf0970aae30e9cdaad91a5deb452a8a19c Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 14:13:23 +0200 Subject: [PATCH 09/28] Fix Prettier formatting in action tests --- .../file-exists/dist/test/__mocks__/fs.d.ts | 7 +++++ .../file-exists/dist/test/__mocks__/fs.js | 26 +++++++++++++++++++ .../file-exists/dist/test/__mocks__/fs.js.map | 1 + action/test/main.spec.ts | 7 ++++- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.d.ts create mode 100644 action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.js create mode 100644 action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.js.map diff --git a/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.d.ts b/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.d.ts new file mode 100644 index 000000000..ab80d332b --- /dev/null +++ b/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.d.ts @@ -0,0 +1,7 @@ +export declare function statSync(...args: any[]): any; +export declare function addStatSyncMock(fn: any): void; +export declare function assertMocksUsed(): void; +declare const mockFs: { + statSync: typeof statSync; +}; +export default mockFs; diff --git a/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.js b/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.js new file mode 100644 index 000000000..cd46c71ca --- /dev/null +++ b/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.js @@ -0,0 +1,26 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +let statSyncMocks = []; +function statSync(...args) { + const mock = statSyncMocks.shift(); + if (typeof mock !== 'function') { + throw new Error(`fs.statSync called without configuring a mock`); + } + return mock(...args); +} +exports.statSync = statSync; +function addStatSyncMock(fn) { + statSyncMocks.push(fn); +} +exports.addStatSyncMock = addStatSyncMock; +function assertMocksUsed() { + if (statSyncMocks.length) { + throw new Error(`fs.afterEach: statSync has ${statSyncMocks.length} unused mocks`); + } +} +exports.assertMocksUsed = assertMocksUsed; +const mockFs = { + statSync, +}; +exports.default = mockFs; +//# sourceMappingURL=fs.js.map \ No newline at end of file diff --git a/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.js.map b/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.js.map new file mode 100644 index 000000000..e2a3d1688 --- /dev/null +++ b/action/node_modules/@kwsites/file-exists/dist/test/__mocks__/fs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../test/__mocks__/fs.ts"],"names":[],"mappings":";;AACA,IAAI,aAAa,GAAU,EAAE,CAAC;AAE9B,SAAgB,QAAQ,CAAC,GAAG,IAAW;IACpC,MAAO,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,CAAC;IACpC,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE;QAC7B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;KACnE;IAED,OAAO,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,CAAC;AAPD,4BAOC;AAED,SAAgB,eAAe,CAAC,EAAO;IACpC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC;AAFD,0CAEC;AAED,SAAgB,eAAe;IAC5B,IAAI,aAAa,CAAC,MAAM,EAAE;QACvB,MAAM,IAAI,KAAK,CAAC,8BAA8B,aAAa,CAAC,MAAM,eAAe,CAAC,CAAC;KACrF;AACJ,CAAC;AAJD,0CAIC;AAED,MAAM,MAAM,GAAG;IACZ,QAAQ;CACV,CAAA;AAED,kBAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/action/test/main.spec.ts b/action/test/main.spec.ts index 9e4be4ef2..78db35020 100644 --- a/action/test/main.spec.ts +++ b/action/test/main.spec.ts @@ -17,7 +17,12 @@ describe('Frogbot Action Tests', () => { describe('Frogbot URL Tests', () => { const myOs: jest.Mocked = os as any; let cases: string[][] = [ - ['win32' as NodeJS.Platform, 'amd64', 'jfrog.exe', 'https://releases.jfrog.io/artifactory/frogbot/v1/1.2.3/frogbot-windows-amd64/jfrog.exe',], + [ + 'win32' as NodeJS.Platform, + 'amd64', + 'jfrog.exe', + 'https://releases.jfrog.io/artifactory/frogbot/v1/1.2.3/frogbot-windows-amd64/jfrog.exe', + ], ['darwin' as NodeJS.Platform, 'amd64', 'jfrog', 'https://releases.jfrog.io/artifactory/frogbot/v1/1.2.3/frogbot-mac-386/jfrog'], ['darwin' as NodeJS.Platform, 'arm64', 'jfrog', 'https://releases.jfrog.io/artifactory/frogbot/v1/1.2.3/frogbot-mac-arm64/jfrog'], ['linux' as NodeJS.Platform, 'amd64', 'jfrog', 'https://releases.jfrog.io/artifactory/frogbot/v1/1.2.3/frogbot-linux-amd64/jfrog'], From 3c4be117c3e79c8f037ced2eabc1c8ce31978b8f Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 14:32:25 +0200 Subject: [PATCH 10/28] Fix buildAndUpload.sh to use dynamic major version (v3) and allow custom repo name --- release/buildAndUpload.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/release/buildAndUpload.sh b/release/buildAndUpload.sh index 4b06a9703..42e122c99 100755 --- a/release/buildAndUpload.sh +++ b/release/buildAndUpload.sh @@ -55,7 +55,11 @@ verifyVersionMatching () { } version="$1" -pkgPath="ecosys-frogbot/v2" +# Extract major version (e.g., "3.1.1" -> "3") +majorVersion="${version%%.*}" +# Allow overriding repository name via environment variable +repoName="${FROGBOT_REPO_NAME:-ecosys-frogbot}" +pkgPath="${repoName}/v${majorVersion}" # Build and upload for every architecture. # Keep 'linux-386' first to prevent unnecessary uploads in case the built version doesn't match the provided one. From e2925ed9f03950b6bce6e02b7eb54a5847a1d469 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 14:50:33 +0200 Subject: [PATCH 11/28] Comment out Go virtual repo config and set local repo for uploads --- .github/workflows/release.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 119a64160..aac950913 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,7 +51,8 @@ jobs: run: | jf c rm --quiet || true jf c add internal --url="$JF_URL" --access-token="$JF_ACCESS_TOKEN" - jf goc --repo-resolve ecosys-go-virtual + # Skip Go config - not needed for fork testing + # jf goc --repo-resolve ecosys-go-virtual - name: Generate mocks run: go generate ./... @@ -110,11 +111,13 @@ jobs: JFROG_CLI_BUILD_NAME: ecosystem-frogbot-release JFROG_CLI_BUILD_NUMBER: ${{ github.run_number }} JFROG_CLI_BUILD_PROJECT: ecosys + FROGBOT_REPO_NAME: ecosys-frogbot-local run: | env -i PATH=$PATH HOME=$HOME \ JFROG_CLI_BUILD_NAME=$JFROG_CLI_BUILD_NAME \ JFROG_CLI_BUILD_NUMBER=$JFROG_CLI_BUILD_NUMBER \ JFROG_CLI_BUILD_PROJECT=$JFROG_CLI_BUILD_PROJECT \ + FROGBOT_REPO_NAME=$FROGBOT_REPO_NAME \ CI=true \ release/buildAndUpload.sh "${{ steps.version.outputs.version }}" From 23c4b83bf555cc62f24abdca523254b4227dc26e Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 15:04:33 +0200 Subject: [PATCH 12/28] Revert repo name change and fix audit to non-blocking (--fail=false) to match old pipeline --- .github/workflows/release.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aac950913..ff36b27c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -57,11 +57,11 @@ jobs: - name: Generate mocks run: go generate ./... - - name: Run JFrog Audit (blocking) + - name: Run JFrog Audit (non-blocking) env: JF_URL: ${{ secrets.JF_URL }} JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }} - run: jf audit --fail=true + run: jf audit --fail=false - name: Set up Node.js for Action uses: actions/setup-node@v4 @@ -111,13 +111,11 @@ jobs: JFROG_CLI_BUILD_NAME: ecosystem-frogbot-release JFROG_CLI_BUILD_NUMBER: ${{ github.run_number }} JFROG_CLI_BUILD_PROJECT: ecosys - FROGBOT_REPO_NAME: ecosys-frogbot-local run: | env -i PATH=$PATH HOME=$HOME \ JFROG_CLI_BUILD_NAME=$JFROG_CLI_BUILD_NAME \ JFROG_CLI_BUILD_NUMBER=$JFROG_CLI_BUILD_NUMBER \ JFROG_CLI_BUILD_PROJECT=$JFROG_CLI_BUILD_PROJECT \ - FROGBOT_REPO_NAME=$FROGBOT_REPO_NAME \ CI=true \ release/buildAndUpload.sh "${{ steps.version.outputs.version }}" From 68780a8a499b49b4e918076c7a15000b5d8b8250 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 15:07:04 +0200 Subject: [PATCH 13/28] Restore jf goc command - required for jf go build in buildAndUpload.sh --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ff36b27c4..da82736d1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,8 +51,8 @@ jobs: run: | jf c rm --quiet || true jf c add internal --url="$JF_URL" --access-token="$JF_ACCESS_TOKEN" - # Skip Go config - not needed for fork testing - # jf goc --repo-resolve ecosys-go-virtual + # Use a generic virtual repo for Go dependencies (or skip if not available) + jf goc --repo-resolve=jfrog-go || echo "Warning: Could not configure Go resolver, continuing anyway" - name: Generate mocks run: go generate ./... From fe0786cab4028b4aded8a0c23551ffdc5feb1095 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 2 Nov 2025 15:08:10 +0200 Subject: [PATCH 14/28] Use ecosys-go-virtual to match original release pipeline --- .github/workflows/release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index da82736d1..f522c5b81 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,8 +51,7 @@ jobs: run: | jf c rm --quiet || true jf c add internal --url="$JF_URL" --access-token="$JF_ACCESS_TOKEN" - # Use a generic virtual repo for Go dependencies (or skip if not available) - jf goc --repo-resolve=jfrog-go || echo "Warning: Could not configure Go resolver, continuing anyway" + jf goc --repo-resolve ecosys-go-virtual - name: Generate mocks run: go generate ./... From 571950ec90bfcc0480b8d5a5bf0dec17c13bc25a Mon Sep 17 00:00:00 2001 From: Keren Reshef Date: Mon, 17 Nov 2025 12:10:50 +0200 Subject: [PATCH 15/28] Fix Python descriptor file resolution bug (#963) * fix python descriptor file resolution * added comment for readability --- packagehandlers/pythonpackagehandler.go | 56 ++++++++++++++++++------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/packagehandlers/pythonpackagehandler.go b/packagehandlers/pythonpackagehandler.go index 34c3c1727..3ff6569ac 100644 --- a/packagehandlers/pythonpackagehandler.go +++ b/packagehandlers/pythonpackagehandler.go @@ -64,23 +64,10 @@ func (py *PythonPackageHandler) handlePip(vulnDetails *utils.VulnerabilityDetail var fixedFile string // This function assumes that the version of the dependencies is statically pinned in the requirements file or inside the 'install_requires' array in the setup.py file fixedPackage := vulnDetails.ImpactedDependencyName + "==" + vulnDetails.SuggestedFixedVersion - if py.pipRequirementsFile == "" { - py.pipRequirementsFile = "setup.py" - } - wd, err := os.Getwd() + currentFile, err := py.tryGetRequirementFile() if err != nil { - return - } - fullPath := filepath.Join(wd, py.pipRequirementsFile) - if !strings.HasPrefix(filepath.Clean(fullPath), wd) { - return errors.New("wrong requirements file input") + return errors.New("failed to read requirements file: " + err.Error()) } - data, err := os.ReadFile(filepath.Clean(py.pipRequirementsFile)) - if err != nil { - return errors.New("an error occurred while attempting to read the requirements file:\n" + err.Error()) - } - currentFile := string(data) - // Check both original and lowered package name and replace to only one lowered result // This regex will match the impactedPackage with it's pinned version e.py. PyJWT==1.7.1 re := regexp.MustCompile(PythonPackageRegexPrefix + "(" + vulnDetails.ImpactedDependencyName + "|" + strings.ToLower(vulnDetails.ImpactedDependencyName) + ")" + PythonPackageRegexSuffix) @@ -95,3 +82,42 @@ func (py *PythonPackageHandler) handlePip(vulnDetails *utils.VulnerabilityDetail } return } + +func (py *PythonPackageHandler) tryGetRequirementFile() (string, error) { + if py.pipRequirementsFile != "" { + fileContent, err := py.tryReadRequirementFile(py.pipRequirementsFile) + if err != nil { + return "", err + } + return fileContent, nil + } else { + // if we don't have a value in py.pipRequirementsFile - we try first setup.py and then requirements.txt + py.pipRequirementsFile = "setup.py" + fileContent, err := py.tryReadRequirementFile(py.pipRequirementsFile) + if err != nil { + py.pipRequirementsFile = "requirements.txt" + fileContent, err = py.tryReadRequirementFile(py.pipRequirementsFile) + if err != nil { + return "", err + } + return fileContent, nil + } + return fileContent, nil + } +} + +func (py *PythonPackageHandler) tryReadRequirementFile(file string) (string, error) { + wd, err := os.Getwd() + if err != nil { + return "", err + } + fullPath := filepath.Join(wd, file) + if !strings.HasPrefix(filepath.Clean(fullPath), wd) { + return "", errors.New("wrong requirements file input: " + fullPath) + } + data, err := os.ReadFile(filepath.Clean(file)) + if err != nil { + return "", errors.New("an error occurred while attempting to read the requirements file:\n" + err.Error()) + } + return string(data), nil +} From 33e2e006b41fdb7f57ac0318bab178058fe107fc Mon Sep 17 00:00:00 2001 From: Or Toren <129293360+orto17@users.noreply.github.com> Date: Thu, 20 Nov 2025 10:59:26 +0200 Subject: [PATCH 16/28] new dependencies (#969) --- go.mod | 28 +++++++++++++-------------- go.sum | 60 +++++++++++++++++++++++++++++----------------------------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index 145e718cd..adc67d943 100644 --- a/go.mod +++ b/go.mod @@ -1,25 +1,25 @@ module github.com/jfrog/frogbot/v2 -go 1.24.6 +go 1.25.4 require ( github.com/CycloneDX/cyclonedx-go v0.9.3 github.com/go-git/go-git/v5 v5.16.3 github.com/golang/mock v1.6.0 github.com/google/go-github/v45 v45.2.0 - github.com/jfrog/build-info-go v1.12.0 - github.com/jfrog/froggit-go v1.20.4 + github.com/jfrog/build-info-go v1.12.4 + github.com/jfrog/froggit-go v1.20.6 github.com/jfrog/gofrog v1.7.6 - github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20251021143342-49bab7f38cec + github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20251118100843-ac34330a70d3 github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20251023084247-a56afca52451 - github.com/jfrog/jfrog-cli-security v1.21.9 - github.com/jfrog/jfrog-client-go v1.55.1-0.20251023073119-78f187c9afbf + github.com/jfrog/jfrog-cli-security v1.22.0 + github.com/jfrog/jfrog-client-go v1.55.1-0.20251119183924-d765eb708cec github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible github.com/owenrumney/go-sarif/v3 v3.2.3 github.com/stretchr/testify v1.11.1 - github.com/urfave/cli/v2 v2.27.4 + github.com/urfave/cli/v2 v2.27.7 github.com/xeipuuv/gojsonschema v1.2.0 - golang.org/x/exp v0.0.0-20250911091902-df9299821621 + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -40,7 +40,7 @@ require ( github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.16.0 // indirect - github.com/forPelevin/gomoji v1.4.0 // indirect + github.com/forPelevin/gomoji v1.4.1 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gfleury/go-bitbucket-v1 v0.0.0-20230825095122-9bc1711434ab // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect @@ -107,15 +107,15 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.43.0 // indirect - golang.org/x/mod v0.28.0 // indirect + golang.org/x/mod v0.29.0 // indirect golang.org/x/net v0.45.0 // indirect golang.org/x/oauth2 v0.31.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.36.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect golang.org/x/text v0.30.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect diff --git a/go.sum b/go.sum index 81e7c3c86..316062643 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,8 @@ github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FM github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/forPelevin/gomoji v1.4.0 h1:RwrT+GimxEtFnGqq4ep1upwR54J5FP84aVAYJA+p8BQ= -github.com/forPelevin/gomoji v1.4.0/go.mod h1:mM6GtmCgpoQP2usDArc6GjbXrti5+FffolyQfGgPboQ= +github.com/forPelevin/gomoji v1.4.1 h1:7U+Bl8o6RV/dOQz7coQFWj/jX6Ram6/cWFOuFDEPEUo= +github.com/forPelevin/gomoji v1.4.1/go.mod h1:mM6GtmCgpoQP2usDArc6GjbXrti5+FffolyQfGgPboQ= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= @@ -128,22 +128,22 @@ github.com/jedib0t/go-pretty/v6 v6.6.8 h1:JnnzQeRz2bACBobIaa/r+nqjvws4yEhcmaZ4n1 github.com/jedib0t/go-pretty/v6 v6.6.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI= github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw= -github.com/jfrog/build-info-go v1.12.0 h1:/abBQdIxrkYjOwO79sIL0p+XPnMCCtKhiWToHKXXqHg= -github.com/jfrog/build-info-go v1.12.0/go.mod h1:szdz9+WzB7+7PGnILLUgyY+OF5qD5geBT7UGNIxibyw= -github.com/jfrog/froggit-go v1.20.4 h1:N9XkNV00HNjpI8p6xXlF9DrWmvE9hz3z2XRDAYJDweQ= -github.com/jfrog/froggit-go v1.20.4/go.mod h1:obSG1SlsWjktkuqmKtpq7MNTTL63e0ot+ucTnlOMV88= +github.com/jfrog/build-info-go v1.12.4 h1:eoHoJDOF7Rx2gAOAXEAjbEIpnH+4y5ha2quQT48Py3Q= +github.com/jfrog/build-info-go v1.12.4/go.mod h1:NEJwH1HxzhtWuiT8eR/anbjT0A3OyLBWpZZrDJs+hWQ= +github.com/jfrog/froggit-go v1.20.6 h1:Xp7+LlEh0m1KGrQstb+u0aGfjRUtv1eh9xQBV3571jQ= +github.com/jfrog/froggit-go v1.20.6/go.mod h1:obSG1SlsWjktkuqmKtpq7MNTTL63e0ot+ucTnlOMV88= github.com/jfrog/gofrog v1.7.6 h1:QmfAiRzVyaI7JYGsB7cxfAJePAZTzFz0gRWZSE27c6s= github.com/jfrog/gofrog v1.7.6/go.mod h1:ntr1txqNOZtHplmaNd7rS4f8jpA5Apx8em70oYEe7+4= github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYLipdsOFMY= github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w= -github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20251021143342-49bab7f38cec h1:iB5bXWKvzNejqyUgqxKf8YNj+DBx1suf2r2KzI03wkU= -github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20251021143342-49bab7f38cec/go.mod h1:JE/35+kU8cBET4I4iuNcVBvhm8SF64DAmGgtHRzf5Do= +github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20251118100843-ac34330a70d3 h1:sIjwBWBmyb7UEqP0IhQ22CWOedOPlNetyHzECS3sUyA= +github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20251118100843-ac34330a70d3/go.mod h1:3hLZrM2xT+PkIevIGret4x1xDFTaVoNu3h374QnrKyc= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20251023084247-a56afca52451 h1:Q0PY8VSOVsfvXzKiUnn+Rv7Ynf901QW6Wn1CbWpHBD0= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20251023084247-a56afca52451/go.mod h1:UOeOwEEmRIi57cRwghN5OBVoqkJieYQQfLpeqw8Yv38= -github.com/jfrog/jfrog-cli-security v1.21.9 h1:QSWADhVE0OYa0SPIc2YhV6QVtuhO6Y+K8rjGHE3MgeY= -github.com/jfrog/jfrog-cli-security v1.21.9/go.mod h1:XoJ6YBf/TrwkqC/r9+x/WKDIwnZogTF6+2wos1PJBUs= -github.com/jfrog/jfrog-client-go v1.55.1-0.20251023073119-78f187c9afbf h1:Ld+lGdCauixqWbkwK+wJn3QbPPBRgY35KgY+MxgrgCg= -github.com/jfrog/jfrog-client-go v1.55.1-0.20251023073119-78f187c9afbf/go.mod h1:jrODQbAbCt97F24d/0bYpqpdc0PFMuBxNJOTfTdW+Fk= +github.com/jfrog/jfrog-cli-security v1.22.0 h1:KNovA+BA1IpE0c0jI6jWF33fOimgylR9a7T84ZmgNJI= +github.com/jfrog/jfrog-cli-security v1.22.0/go.mod h1:uoACrGyWZViNPU0STC0fF38bVKtNXjm3hzWW/DKI0DY= +github.com/jfrog/jfrog-client-go v1.55.1-0.20251119183924-d765eb708cec h1:tNfeGi/2FuxIUSi8urFZuqa33grynAHwLRH6iIK/DB0= +github.com/jfrog/jfrog-client-go v1.55.1-0.20251119183924-d765eb708cec/go.mod h1:ureS+L3wNs0qYUBSwH8C9PjwnraTX9ibZu7JkaqjO/E= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA= @@ -206,8 +206,8 @@ github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9l github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/owenrumney/go-sarif/v3 v3.2.3 h1:n6mdX5ugKwCrZInvBsf6WumXmpAe3mbmQXgkXlIq34U= github.com/owenrumney/go-sarif/v3 v3.2.3/go.mod h1:1bV7t8SZg7pX41spaDkEUs8/yEjzk9JapztMoX1XNjg= github.com/package-url/packageurl-go v0.1.3 h1:4juMED3hHiz0set3Vq3KeQ75KD1avthoXLtmE3I0PLs= @@ -278,8 +278,8 @@ github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ= github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo= -github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8= -github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= +github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= +github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/vbauerster/mpb/v8 v8.10.2 h1:2uBykSHAYHekE11YvJhKxYmLATKHAGorZwFlyNw4hHM= github.com/vbauerster/mpb/v8 v8.10.2/go.mod h1:+Ja4P92E3/CorSZgfDtK46D7AVbDqmBQRTmyTqPElo0= github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo= @@ -299,8 +299,8 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofm github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg= +github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -315,13 +315,13 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= -golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= -golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -347,8 +347,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -380,16 +380,16 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -406,8 +406,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 893d9dfc64b4249f7d3ab4139f946af8bc792602 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 23 Nov 2025 14:55:02 +0200 Subject: [PATCH 17/28] changed release method --- .github/workflows/release.yml | 131 +++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 34 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f522c5b81..e54a73841 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,12 @@ name: Release Frogbot on: - release: - types: [published] + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g., 3.0.1)' + required: true + type: string # Required permissions permissions: @@ -14,23 +18,34 @@ jobs: name: Release Frogbot v3 runs-on: ubuntu-latest - # Only run for v3.x.x releases - if: startsWith(github.event.release.tag_name, 'v3.') - steps: - name: Extract version from tag id: version run: | - TAG="${{ github.event.release.tag_name }}" - VERSION="${TAG#v}" + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + # Manual trigger: use input version + VERSION="${{ inputs.version }}" + # Add 'v' prefix if not present + if [[ ! "$VERSION" =~ ^v ]]; then + TAG="v$VERSION" + else + TAG="$VERSION" + VERSION="${VERSION#v}" + fi + else + # Release trigger: use release tag + TAG="${{ github.event.release.tag_name }}" + VERSION="${TAG#v}" + fi echo "version=$VERSION" >> $GITHUB_OUTPUT echo "tag=$TAG" >> $GITHUB_OUTPUT echo "Release version: $VERSION" + echo "Release tag: $TAG" - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.release.tag_name }} + ref: ${{ github.event_name == 'workflow_dispatch' && github.ref || github.event.release.tag_name }} fetch-depth: 0 - name: Set up Go @@ -83,19 +98,24 @@ jobs: git config user.email "github-actions[bot]@users.noreply.github.com" git add action/lib/ - # Only commit and update tag if there are changes + # Check if there are changes + CHANGES=false if ! git diff --staged --quiet; then - echo "Action files changed, updating tag..." + echo "Action files changed, committing..." git commit -m "Build action for ${{ steps.version.outputs.tag }}" - - # Update the release tag to point to the new commit - git tag -f ${{ steps.version.outputs.tag }} - git push origin ${{ steps.version.outputs.tag }} --force - - echo "Tag updated with compiled action" + CHANGES=true else echo "No changes to action files" fi + + # For manual triggers, always create/update the tag + # For release triggers, update the tag only if there were changes + if [ "${{ github.event_name }}" == "workflow_dispatch" ] || [ "$CHANGES" = "true" ]; then + echo "Creating/updating tag ${{ steps.version.outputs.tag }}..." + git tag -f ${{ steps.version.outputs.tag }} + git push origin ${{ steps.version.outputs.tag }} --force + echo "Tag ${{ steps.version.outputs.tag }} created/updated" + fi - name: Update GitHub Action major version tag (v3) run: | @@ -140,6 +160,30 @@ jobs: --site="releases.jfrog.io" \ --sync + - name: Create GitHub Release + if: github.event_name == 'workflow_dispatch' + uses: actions/github-script@v7 + with: + script: | + const tag = '${{ steps.version.outputs.tag }}'; + + console.log(`Creating release for tag ${tag}`); + + // The tag was already created and pushed in the previous step + // Now create the release with auto-generated notes + const release = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: tag, + name: `Release ${tag}`, + generate_release_notes: true, + draft: false, + prerelease: false + }); + + console.log(`Created release ${release.data.id} for ${tag}`); + console.log(`Release URL: ${release.data.html_url}`); + - name: Cleanup JFrog config if: always() run: jf c rm --quiet || true @@ -150,24 +194,43 @@ jobs: uses: actions/github-script@v7 with: script: | - const release_id = context.payload.release.id; - const tag = context.payload.release.tag_name; - - console.log(`Deleting release ${release_id} and tag ${tag}`); + const tag = '${{ steps.version.outputs.tag }}'; - // Delete the release - await github.rest.repos.deleteRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: release_id - }); - - // Delete the tag - await github.rest.git.deleteRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `tags/${tag}` - }); + console.log(`Workflow failed, cleaning up tag ${tag}`); - console.log('Release and tag deleted successfully'); + try { + // Try to find and delete the release + const releases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo + }); + + const release = releases.data.find(r => r.tag_name === tag); + if (release) { + console.log(`Deleting release ${release.id}`); + await github.rest.repos.deleteRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id + }); + console.log('Release deleted'); + } else { + console.log('No release found to delete'); + } + + // Delete the tag + try { + await github.rest.git.deleteRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `tags/${tag}` + }); + console.log('Tag deleted'); + } catch (error) { + console.log(`Tag deletion failed or tag doesn't exist: ${error.message}`); + } + } catch (error) { + console.error(`Cleanup failed: ${error.message}`); + // Don't fail the workflow if cleanup fails + } From f48bf95fc20db10b8ea3ce9a0bcb6241e235dc24 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Sun, 23 Nov 2025 15:32:26 +0200 Subject: [PATCH 18/28] Add manual trigger for release workflow with version validation - Add workflow_dispatch trigger with version input parameter - Validate version is v3.x.x format - Check if tag already exists before proceeding - Auto-generate release notes at the end - Set make_latest=false to not mark as latest release - Improve failure cleanup to work with both trigger types --- .github/workflows/release.yml | 51 ++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e54a73841..290e298c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,6 +32,13 @@ jobs: TAG="$VERSION" VERSION="${VERSION#v}" fi + + # Validate it's a v3.x.x version + if [[ ! "$TAG" =~ ^v3\.[0-9]+\.[0-9]+$ ]]; then + echo "❌ Error: Version must be v3.x.x format (e.g., v3.0.1)" + echo "Got: $TAG" + exit 1 + fi else # Release trigger: use release tag TAG="${{ github.event.release.tag_name }}" @@ -39,8 +46,35 @@ jobs: fi echo "version=$VERSION" >> $GITHUB_OUTPUT echo "tag=$TAG" >> $GITHUB_OUTPUT - echo "Release version: $VERSION" - echo "Release tag: $TAG" + echo "βœ… Release version: $VERSION" + echo "βœ… Release tag: $TAG" + + - name: Check if tag already exists + if: github.event_name == 'workflow_dispatch' + uses: actions/github-script@v7 + with: + script: | + const tag = '${{ steps.version.outputs.tag }}'; + + try { + // Check if tag exists + await github.rest.git.getRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `tags/${tag}` + }); + + // Tag exists - fail the workflow + core.setFailed(`❌ Tag ${tag} already exists! Please use a different version.`); + } catch (error) { + if (error.status === 404) { + // Tag doesn't exist - good to proceed + console.log(`βœ… Tag ${tag} does not exist, proceeding with release`); + } else { + // Some other error + throw error; + } + } - name: Checkout code uses: actions/checkout@v4 @@ -75,9 +109,9 @@ jobs: env: JF_URL: ${{ secrets.JF_URL }} JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }} - run: jf audit --fail=false + run: jf audit --fail=true - - name: Set up Node.js for Action + - name: Set up Node.js for ActionØ uses: actions/setup-node@v4 with: node-version: '16' @@ -171,6 +205,7 @@ jobs: // The tag was already created and pushed in the previous step // Now create the release with auto-generated notes + // Note: make_latest is set to false so this doesn't become the "Latest" release const release = await github.rest.repos.createRelease({ owner: context.repo.owner, repo: context.repo.repo, @@ -178,11 +213,13 @@ jobs: name: `Release ${tag}`, generate_release_notes: true, draft: false, - prerelease: false + prerelease: false, + make_latest: false }); - console.log(`Created release ${release.data.id} for ${tag}`); - console.log(`Release URL: ${release.data.html_url}`); + console.log(`βœ… Created release ${release.data.id} for ${tag}`); + console.log(`πŸ“¦ Release URL: ${release.data.html_url}`); + console.log(`ℹ️ This release is NOT marked as "Latest"`); - name: Cleanup JFrog config if: always() From 040402e2763a982b003e3a4fe07fbbdcfb0f0067 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 16:13:50 +0200 Subject: [PATCH 19/28] Parallelize binary builds using Go goroutines - Create Go builder tool that builds all 10 platform binaries concurrently - Replace sequential bash script with parallel Go implementation - Build linux-386 first for version verification, then build remaining 9 in parallel - Should significantly reduce build time from ~10+ minutes to ~2-3 minutes - All builds run concurrently without worker limits for maximum speed --- .github/workflows/release.yml | 10 +- release/builder/main.go | 201 ++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 release/builder/main.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 290e298c4..ceb483edd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -158,19 +158,25 @@ jobs: git push origin v3 --force echo "Updated v3 tag to ${{ steps.version.outputs.tag }}" - - name: Build and upload binaries + - name: Build and upload binaries (parallel with goroutines) env: VERSION: ${{ steps.version.outputs.tag }} JFROG_CLI_BUILD_NAME: ecosystem-frogbot-release JFROG_CLI_BUILD_NUMBER: ${{ github.run_number }} JFROG_CLI_BUILD_PROJECT: ecosys run: | + # Build the parallel builder tool + cd release/builder + go build -o builder . + cd ../.. + + # Run the parallel builder env -i PATH=$PATH HOME=$HOME \ JFROG_CLI_BUILD_NAME=$JFROG_CLI_BUILD_NAME \ JFROG_CLI_BUILD_NUMBER=$JFROG_CLI_BUILD_NUMBER \ JFROG_CLI_BUILD_PROJECT=$JFROG_CLI_BUILD_PROJECT \ CI=true \ - release/buildAndUpload.sh "${{ steps.version.outputs.version }}" + ./release/builder/builder "${{ steps.version.outputs.version }}" - name: Publish build info env: diff --git a/release/builder/main.go b/release/builder/main.go new file mode 100644 index 000000000..efc27f915 --- /dev/null +++ b/release/builder/main.go @@ -0,0 +1,201 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" +) + +type buildTarget struct { + pkg string + goos string + goarch string + fileExtension string +} + +func main() { + if len(os.Args) < 2 { + fmt.Fprintln(os.Stderr, "Usage: builder ") + os.Exit(1) + } + + version := os.Args[1] + pkgPath := "ecosys-frogbot/v2" + + // All build targets + targets := []buildTarget{ + {"frogbot-linux-386", "linux", "386", ""}, + {"frogbot-linux-amd64", "linux", "amd64", ""}, + {"frogbot-linux-s390x", "linux", "s390x", ""}, + {"frogbot-linux-arm64", "linux", "arm64", ""}, + {"frogbot-linux-arm", "linux", "arm", ""}, + {"frogbot-linux-ppc64", "linux", "ppc64", ""}, + {"frogbot-linux-ppc64le", "linux", "ppc64le", ""}, + {"frogbot-mac-386", "darwin", "amd64", ""}, + {"frogbot-mac-arm64", "darwin", "arm64", ""}, + {"frogbot-windows-amd64", "windows", "amd64", ".exe"}, + } + + // Build linux-386 first and verify version + fmt.Println("Building and verifying linux-386 first...") + if err := buildAndUpload(targets[0], version, pkgPath, true); err != nil { + fmt.Fprintf(os.Stderr, "Error building linux-386: %v\n", err) + os.Exit(1) + } + + // Build remaining targets in parallel (all at once!) + fmt.Printf("\nBuilding remaining %d targets in parallel...\n\n", len(targets)-1) + + var wg sync.WaitGroup + errorsChan := make(chan error, len(targets)-1) + + // Launch all builds concurrently + for i := 1; i < len(targets); i++ { + wg.Add(1) + go func(target buildTarget) { + defer wg.Done() + if err := buildAndUpload(target, version, pkgPath, false); err != nil { + errorsChan <- fmt.Errorf("%s: %w", target.pkg, err) + } + }(targets[i]) + } + + // Wait for all builds to complete + wg.Wait() + close(errorsChan) + + // Collect errors + var errors []string + for err := range errorsChan { + errors = append(errors, err.Error()) + } + + if len(errors) > 0 { + fmt.Fprintln(os.Stderr, "\nBuild errors occurred:") + for _, err := range errors { + fmt.Fprintf(os.Stderr, " - %s\n", err) + } + os.Exit(1) + } + + // Upload the getFrogbot.sh script + fmt.Println("\nUploading getFrogbot.sh...") + if err := uploadFile("./buildscripts/getFrogbot.sh", fmt.Sprintf("%s/%s/", pkgPath, version)); err != nil { + fmt.Fprintf(os.Stderr, "Error uploading getFrogbot.sh: %v\n", err) + os.Exit(1) + } + + fmt.Println("\nβœ… All builds completed successfully!") +} + +func buildAndUpload(target buildTarget, version, pkgPath string, verify bool) error { + exeName := "frogbot" + target.fileExtension + + // Build + if err := build(target, exeName, version); err != nil { + return fmt.Errorf("build failed: %w", err) + } + + // Verify version (only for linux-386) + if verify { + if err := verifyVersion(exeName, version); err != nil { + return fmt.Errorf("version verification failed: %w", err) + } + } + + // Upload + destPath := fmt.Sprintf("%s/%s/%s/%s", pkgPath, version, target.pkg, exeName) + if err := upload(exeName, destPath); err != nil { + return fmt.Errorf("upload failed: %w", err) + } + + return nil +} + +func build(target buildTarget, exeName, version string) error { + fmt.Printf("πŸ”¨ Building %s for %s-%s...\n", exeName, target.goos, target.goarch) + + ldflags := fmt.Sprintf("-w -extldflags \"-static\" -X github.com/jfrog/frogbot/v2/utils.FrogbotVersion=%s", version) + + cmd := exec.Command("jf", "go", "build", "-o", exeName, "-ldflags", ldflags) + cmd.Env = append(os.Environ(), + "CGO_ENABLED=0", + "GOOS="+target.goos, + "GOARCH="+target.goarch, + ) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + return err + } + + // Make executable + if err := os.Chmod(exeName, 0755); err != nil { + return fmt.Errorf("chmod failed: %w", err) + } + + fmt.Printf("βœ… Built %s\n", exeName) + return nil +} + +func verifyVersion(exeName, expectedVersion string) error { + fmt.Println("πŸ” Verifying version matches...") + + cmd := exec.Command("./"+exeName, "-v") + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to run -v: %w", err) + } + + outputStr := strings.TrimSpace(string(output)) + fmt.Printf("Output: %s\n", outputStr) + + // Get the version which is after the last space + parts := strings.Fields(outputStr) + if len(parts) == 0 { + return fmt.Errorf("unexpected version output format") + } + builtVersion := parts[len(parts)-1] + + if builtVersion != expectedVersion { + return fmt.Errorf("versions don't match. Provided: %s, Actual: %s", expectedVersion, builtVersion) + } + + fmt.Println("βœ… Versions match") + return nil +} + +func upload(sourcePath, destPath string) error { + fmt.Printf("πŸ“¦ Uploading %s to %s...\n", sourcePath, destPath) + + cmd := exec.Command("jf", "rt", "u", sourcePath, destPath) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + return err + } + + // Clean up the built binary after upload + if err := os.Remove(sourcePath); err != nil { + // Don't fail if cleanup fails + fmt.Printf("Warning: failed to remove %s: %v\n", sourcePath, err) + } + + fmt.Printf("βœ… Uploaded %s\n", filepath.Base(sourcePath)) + return nil +} + +func uploadFile(sourcePath, destPath string) error { + fmt.Printf("πŸ“¦ Uploading %s to %s...\n", sourcePath, destPath) + + cmd := exec.Command("jf", "rt", "u", sourcePath, destPath, "--flat") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + return cmd.Run() +} From 512e2d81066f15912480ea1ec43a158423bf40da Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 16:39:31 +0200 Subject: [PATCH 20/28] Parallelize binary builds using bash background jobs - Update buildAndUpload.sh to run 9 builds in parallel using & background jobs - Build linux-386 first for version verification, then all others concurrently - Simpler solution than Go - just ~20 lines added to existing bash script - All builds run on same runner, no worker limits for maximum speed - Should reduce build time from ~10-15 minutes to ~2-3 minutes --- .github/workflows/release.yml | 10 +- release/buildAndUpload.sh | 41 +++++-- release/builder/main.go | 201 ---------------------------------- 3 files changed, 34 insertions(+), 218 deletions(-) delete mode 100644 release/builder/main.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ceb483edd..0c2172424 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -158,25 +158,19 @@ jobs: git push origin v3 --force echo "Updated v3 tag to ${{ steps.version.outputs.tag }}" - - name: Build and upload binaries (parallel with goroutines) + - name: Build and upload binaries (parallel) env: VERSION: ${{ steps.version.outputs.tag }} JFROG_CLI_BUILD_NAME: ecosystem-frogbot-release JFROG_CLI_BUILD_NUMBER: ${{ github.run_number }} JFROG_CLI_BUILD_PROJECT: ecosys run: | - # Build the parallel builder tool - cd release/builder - go build -o builder . - cd ../.. - - # Run the parallel builder env -i PATH=$PATH HOME=$HOME \ JFROG_CLI_BUILD_NAME=$JFROG_CLI_BUILD_NAME \ JFROG_CLI_BUILD_NUMBER=$JFROG_CLI_BUILD_NUMBER \ JFROG_CLI_BUILD_PROJECT=$JFROG_CLI_BUILD_PROJECT \ CI=true \ - ./release/builder/builder "${{ steps.version.outputs.version }}" + release/buildAndUpload.sh "${{ steps.version.outputs.version }}" - name: Publish build info env: diff --git a/release/buildAndUpload.sh b/release/buildAndUpload.sh index 42e122c99..00b9f7ebb 100755 --- a/release/buildAndUpload.sh +++ b/release/buildAndUpload.sh @@ -63,16 +63,39 @@ pkgPath="${repoName}/v${majorVersion}" # Build and upload for every architecture. # Keep 'linux-386' first to prevent unnecessary uploads in case the built version doesn't match the provided one. +echo "Building linux-386 first for version verification..." buildAndUpload 'frogbot-linux-386' 'linux' '386' '' -buildAndUpload 'frogbot-linux-amd64' 'linux' 'amd64' '' -buildAndUpload 'frogbot-linux-s390x' 'linux' 's390x' '' -buildAndUpload 'frogbot-linux-arm64' 'linux' 'arm64' '' -buildAndUpload 'frogbot-linux-arm' 'linux' 'arm' '' -buildAndUpload 'frogbot-linux-ppc64' 'linux' 'ppc64' '' -buildAndUpload 'frogbot-linux-ppc64le' 'linux' 'ppc64le' '' -buildAndUpload 'frogbot-mac-386' 'darwin' 'amd64' '' -buildAndUpload 'frogbot-mac-arm64' 'darwin' 'arm64' '' -buildAndUpload 'frogbot-windows-amd64' 'windows' 'amd64' '.exe' + +# Build the rest in parallel for speed +echo "" +echo "Building remaining 9 platforms in parallel..." +pids=() + +buildAndUpload 'frogbot-linux-amd64' 'linux' 'amd64' '' & pids+=($!) +buildAndUpload 'frogbot-linux-s390x' 'linux' 's390x' '' & pids+=($!) +buildAndUpload 'frogbot-linux-arm64' 'linux' 'arm64' '' & pids+=($!) +buildAndUpload 'frogbot-linux-arm' 'linux' 'arm' '' & pids+=($!) +buildAndUpload 'frogbot-linux-ppc64' 'linux' 'ppc64' '' & pids+=($!) +buildAndUpload 'frogbot-linux-ppc64le' 'linux' 'ppc64le' '' & pids+=($!) +buildAndUpload 'frogbot-mac-386' 'darwin' 'amd64' '' & pids+=($!) +buildAndUpload 'frogbot-mac-arm64' 'darwin' 'arm64' '' & pids+=($!) +buildAndUpload 'frogbot-windows-amd64' 'windows' 'amd64' '.exe' & pids+=($!) + +# Wait for all background jobs and check for failures +echo "Waiting for all parallel builds to complete..." +failed=0 +for pid in "${pids[@]}"; do + wait $pid || failed=1 +done + +if [ $failed -eq 1 ]; then + echo "❌ One or more builds failed!" + exit 1 +fi + +echo "" +echo "βœ… All builds completed successfully!" +echo "" jf rt u "./buildscripts/getFrogbot.sh" "$pkgPath/$version/" --flat diff --git a/release/builder/main.go b/release/builder/main.go deleted file mode 100644 index efc27f915..000000000 --- a/release/builder/main.go +++ /dev/null @@ -1,201 +0,0 @@ -package main - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "sync" -) - -type buildTarget struct { - pkg string - goos string - goarch string - fileExtension string -} - -func main() { - if len(os.Args) < 2 { - fmt.Fprintln(os.Stderr, "Usage: builder ") - os.Exit(1) - } - - version := os.Args[1] - pkgPath := "ecosys-frogbot/v2" - - // All build targets - targets := []buildTarget{ - {"frogbot-linux-386", "linux", "386", ""}, - {"frogbot-linux-amd64", "linux", "amd64", ""}, - {"frogbot-linux-s390x", "linux", "s390x", ""}, - {"frogbot-linux-arm64", "linux", "arm64", ""}, - {"frogbot-linux-arm", "linux", "arm", ""}, - {"frogbot-linux-ppc64", "linux", "ppc64", ""}, - {"frogbot-linux-ppc64le", "linux", "ppc64le", ""}, - {"frogbot-mac-386", "darwin", "amd64", ""}, - {"frogbot-mac-arm64", "darwin", "arm64", ""}, - {"frogbot-windows-amd64", "windows", "amd64", ".exe"}, - } - - // Build linux-386 first and verify version - fmt.Println("Building and verifying linux-386 first...") - if err := buildAndUpload(targets[0], version, pkgPath, true); err != nil { - fmt.Fprintf(os.Stderr, "Error building linux-386: %v\n", err) - os.Exit(1) - } - - // Build remaining targets in parallel (all at once!) - fmt.Printf("\nBuilding remaining %d targets in parallel...\n\n", len(targets)-1) - - var wg sync.WaitGroup - errorsChan := make(chan error, len(targets)-1) - - // Launch all builds concurrently - for i := 1; i < len(targets); i++ { - wg.Add(1) - go func(target buildTarget) { - defer wg.Done() - if err := buildAndUpload(target, version, pkgPath, false); err != nil { - errorsChan <- fmt.Errorf("%s: %w", target.pkg, err) - } - }(targets[i]) - } - - // Wait for all builds to complete - wg.Wait() - close(errorsChan) - - // Collect errors - var errors []string - for err := range errorsChan { - errors = append(errors, err.Error()) - } - - if len(errors) > 0 { - fmt.Fprintln(os.Stderr, "\nBuild errors occurred:") - for _, err := range errors { - fmt.Fprintf(os.Stderr, " - %s\n", err) - } - os.Exit(1) - } - - // Upload the getFrogbot.sh script - fmt.Println("\nUploading getFrogbot.sh...") - if err := uploadFile("./buildscripts/getFrogbot.sh", fmt.Sprintf("%s/%s/", pkgPath, version)); err != nil { - fmt.Fprintf(os.Stderr, "Error uploading getFrogbot.sh: %v\n", err) - os.Exit(1) - } - - fmt.Println("\nβœ… All builds completed successfully!") -} - -func buildAndUpload(target buildTarget, version, pkgPath string, verify bool) error { - exeName := "frogbot" + target.fileExtension - - // Build - if err := build(target, exeName, version); err != nil { - return fmt.Errorf("build failed: %w", err) - } - - // Verify version (only for linux-386) - if verify { - if err := verifyVersion(exeName, version); err != nil { - return fmt.Errorf("version verification failed: %w", err) - } - } - - // Upload - destPath := fmt.Sprintf("%s/%s/%s/%s", pkgPath, version, target.pkg, exeName) - if err := upload(exeName, destPath); err != nil { - return fmt.Errorf("upload failed: %w", err) - } - - return nil -} - -func build(target buildTarget, exeName, version string) error { - fmt.Printf("πŸ”¨ Building %s for %s-%s...\n", exeName, target.goos, target.goarch) - - ldflags := fmt.Sprintf("-w -extldflags \"-static\" -X github.com/jfrog/frogbot/v2/utils.FrogbotVersion=%s", version) - - cmd := exec.Command("jf", "go", "build", "-o", exeName, "-ldflags", ldflags) - cmd.Env = append(os.Environ(), - "CGO_ENABLED=0", - "GOOS="+target.goos, - "GOARCH="+target.goarch, - ) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if err := cmd.Run(); err != nil { - return err - } - - // Make executable - if err := os.Chmod(exeName, 0755); err != nil { - return fmt.Errorf("chmod failed: %w", err) - } - - fmt.Printf("βœ… Built %s\n", exeName) - return nil -} - -func verifyVersion(exeName, expectedVersion string) error { - fmt.Println("πŸ” Verifying version matches...") - - cmd := exec.Command("./"+exeName, "-v") - output, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("failed to run -v: %w", err) - } - - outputStr := strings.TrimSpace(string(output)) - fmt.Printf("Output: %s\n", outputStr) - - // Get the version which is after the last space - parts := strings.Fields(outputStr) - if len(parts) == 0 { - return fmt.Errorf("unexpected version output format") - } - builtVersion := parts[len(parts)-1] - - if builtVersion != expectedVersion { - return fmt.Errorf("versions don't match. Provided: %s, Actual: %s", expectedVersion, builtVersion) - } - - fmt.Println("βœ… Versions match") - return nil -} - -func upload(sourcePath, destPath string) error { - fmt.Printf("πŸ“¦ Uploading %s to %s...\n", sourcePath, destPath) - - cmd := exec.Command("jf", "rt", "u", sourcePath, destPath) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if err := cmd.Run(); err != nil { - return err - } - - // Clean up the built binary after upload - if err := os.Remove(sourcePath); err != nil { - // Don't fail if cleanup fails - fmt.Printf("Warning: failed to remove %s: %v\n", sourcePath, err) - } - - fmt.Printf("βœ… Uploaded %s\n", filepath.Base(sourcePath)) - return nil -} - -func uploadFile(sourcePath, destPath string) error { - fmt.Printf("πŸ“¦ Uploading %s to %s...\n", sourcePath, destPath) - - cmd := exec.Command("jf", "rt", "u", sourcePath, destPath, "--flat") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - return cmd.Run() -} From 282c943bb6d8153511ba478897975ef81c1a9042 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 16:54:38 +0200 Subject: [PATCH 21/28] Fix parallel build race condition - Each build now outputs to unique filename (e.g., frogbot-linux-amd64) - Prevents parallel builds from overwriting each other's binaries - Upload still uses correct final name 'frogbot' at destination - Fixes checksum mismatch errors when uploading --- release/buildAndUpload.sh | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/release/buildAndUpload.sh b/release/buildAndUpload.sh index 00b9f7ebb..eb6e1e16f 100755 --- a/release/buildAndUpload.sh +++ b/release/buildAndUpload.sh @@ -14,7 +14,7 @@ build () { # Run verification after building plugin for the correct platform of this image. if [[ "$pkg" = "frogbot-linux-386" ]]; then - verifyVersionMatching + verifyVersionMatching "$exeName" fi } @@ -24,19 +24,26 @@ buildAndUpload () { goos="$2" goarch="$3" fileExtension="$4" - exeName="frogbot$fileExtension" - - build "$pkg" "$goos" "$goarch" "$exeName" - - destPath="$pkgPath/$version/$pkg/$exeName" - echo "Uploading $exeName to $destPath ..." - jf rt u "./$exeName" "$destPath" + # Use unique filename during build to avoid parallel conflicts + uniqueExeName="${pkg}${fileExtension}" + finalExeName="frogbot$fileExtension" + + build "$pkg" "$goos" "$goarch" "$uniqueExeName" + + destPath="$pkgPath/$version/$pkg/$finalExeName" + echo "Uploading $uniqueExeName to $destPath ..." + jf rt u "./$uniqueExeName" "$destPath" + + # Clean up the unique build file after upload + rm -f "./$uniqueExeName" } # Verify version provided in pipelines UI matches version in frogbot source code. +# Takes the executable name as parameter verifyVersionMatching () { + local exePath="$1" echo "Verifying provided version matches built version..." - res=$(eval "./frogbot -v") + res=$(eval "./$exePath -v") exitCode=$? if [[ $exitCode -ne 0 ]]; then echo "Error: Failed verifying version matches" From 024f2dc86808e5c5ed00f9e56a31889905c53034 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 17:09:11 +0200 Subject: [PATCH 22/28] Pre-download Go dependencies before parallel builds - Add step to download all dependencies once before parallel builds start - Runs go mod download and go list to populate cache - Prevents 9 parallel builds from racing to download same dependencies - Should reduce parallel build time by avoiding redundant work --- .github/workflows/release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c2172424..4b0a45b62 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -158,6 +158,13 @@ jobs: git push origin v3 --force echo "Updated v3 tag to ${{ steps.version.outputs.tag }}" + - name: Pre-download Go dependencies + run: | + echo "Pre-downloading all dependencies to avoid parallel build contention..." + go mod download + go list -mod=mod -m all + echo "βœ… Dependencies cached and ready for parallel builds" + - name: Build and upload binaries (parallel) env: VERSION: ${{ steps.version.outputs.tag }} From 47eb21c390bf9eca614cbf70d27fbb31fbefd7a5 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 17:13:11 +0200 Subject: [PATCH 23/28] Replace JFrog Audit with Frogbot scan (dogfooding) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove jf audit step - Build and run Frogbot scan-repository on itself - True dogfooding: Frogbot scanning Frogbot 🐸 - Fails if vulnerabilities found --- .github/workflows/release.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4b0a45b62..a04e6b8ec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -105,11 +105,19 @@ jobs: - name: Generate mocks run: go generate ./... - - name: Run JFrog Audit (non-blocking) + - name: Run Frogbot on Frogbot (dogfooding 🐸) env: JF_URL: ${{ secrets.JF_URL }} JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }} - run: jf audit --fail=true + JF_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JF_GIT_BASE_BRANCH: ${{ github.ref_name }} + JF_FAIL: "true" + run: | + echo "Building Frogbot binary..." + go build -o frogbot-scan + + echo "Running Frogbot scan on itself (dogfooding!)..." + ./frogbot-scan scan-repository - name: Set up Node.js for ActionØ uses: actions/setup-node@v4 From 2f21dc6850ef32de20dfc073720fab8db93bdda4 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 17:27:53 +0200 Subject: [PATCH 24/28] Remove pre-download step and clean up Frogbot step name --- .github/workflows/release.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a04e6b8ec..559539aaf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -105,7 +105,7 @@ jobs: - name: Generate mocks run: go generate ./... - - name: Run Frogbot on Frogbot (dogfooding 🐸) + - name: Run Frogbot on Frogbot env: JF_URL: ${{ secrets.JF_URL }} JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }} @@ -116,7 +116,7 @@ jobs: echo "Building Frogbot binary..." go build -o frogbot-scan - echo "Running Frogbot scan on itself (dogfooding!)..." + echo "Running Frogbot scan before release..." ./frogbot-scan scan-repository - name: Set up Node.js for ActionØ @@ -166,13 +166,6 @@ jobs: git push origin v3 --force echo "Updated v3 tag to ${{ steps.version.outputs.tag }}" - - name: Pre-download Go dependencies - run: | - echo "Pre-downloading all dependencies to avoid parallel build contention..." - go mod download - go list -mod=mod -m all - echo "βœ… Dependencies cached and ready for parallel builds" - - name: Build and upload binaries (parallel) env: VERSION: ${{ steps.version.outputs.tag }} From 9670eb9f4ca948ba6a4d3a816eeef812d0f7d7b9 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 17:37:00 +0200 Subject: [PATCH 25/28] Use Frogbot action instead of building manually - Replace manual go build + run with jfrog/frogbot@v2 action - Simpler, faster, and more reliable - Added JF_FAIL flag to fail on security issues --- .github/workflows/release.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 559539aaf..4cda12edc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -105,19 +105,14 @@ jobs: - name: Generate mocks run: go generate ./... - - name: Run Frogbot on Frogbot + - name: Run Frogbot scan before release + uses: jfrog/frogbot@v2 env: JF_URL: ${{ secrets.JF_URL }} JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }} JF_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} JF_GIT_BASE_BRANCH: ${{ github.ref_name }} JF_FAIL: "true" - run: | - echo "Building Frogbot binary..." - go build -o frogbot-scan - - echo "Running Frogbot scan before release..." - ./frogbot-scan scan-repository - name: Set up Node.js for ActionØ uses: actions/setup-node@v4 From 95dd5a259a51b8f479c2910787222177f79855b7 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 17:44:23 +0200 Subject: [PATCH 26/28] Add JF_SKIP_AUTOFIX flag to prevent Frogbot from creating fix PRs - Frogbot will scan and fail on issues - Won't attempt to create automatic fix pull requests --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4cda12edc..2897d5e1d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,6 +113,7 @@ jobs: JF_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }} JF_GIT_BASE_BRANCH: ${{ github.ref_name }} JF_FAIL: "true" + JF_SKIP_AUTOFIX: "true" - name: Set up Node.js for ActionØ uses: actions/setup-node@v4 From edfd4252fd904e456b95b1a79bd03712cd664931 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 18:07:32 +0200 Subject: [PATCH 27/28] Optimize build: replace jf go build with regular go build - Replace 'jf go build' with 'go build' to remove JFrog CLI overhead - Add cache warmup step before parallel builds - Pre-download dependencies once - Warm up Go build cache with initial build - Should significantly reduce parallel build time from 6min to 2-3min --- .github/workflows/release.yml | 9 +++++++++ release/buildAndUpload.sh | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2897d5e1d..358120b0b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -162,6 +162,15 @@ jobs: git push origin v3 --force echo "Updated v3 tag to ${{ steps.version.outputs.tag }}" + - name: Warm up Go caches for fast parallel builds + run: | + echo "πŸ“¦ Pre-downloading all dependencies..." + go mod download + echo "πŸ”₯ Warming up build cache with quick build..." + go build -o /tmp/frogbot-warmup + rm /tmp/frogbot-warmup + echo "βœ… Caches ready - parallel builds should be blazing fast!" + - name: Build and upload binaries (parallel) env: VERSION: ${{ steps.version.outputs.tag }} diff --git a/release/buildAndUpload.sh b/release/buildAndUpload.sh index eb6e1e16f..a21058874 100755 --- a/release/buildAndUpload.sh +++ b/release/buildAndUpload.sh @@ -9,7 +9,7 @@ build () { exeName="$4" echo "Building $exeName for $GOOS-$GOARCH ..." - CGO_ENABLED=0 jf go build -o "$exeName" -ldflags '-w -extldflags "-static" -X github.com/jfrog/frogbot/v2/utils.FrogbotVersion='"$version" + CGO_ENABLED=0 go build -o "$exeName" -ldflags '-w -extldflags "-static" -X github.com/jfrog/frogbot/v2/utils.FrogbotVersion='"$version" chmod +x "$exeName" # Run verification after building plugin for the correct platform of this image. From f04898809cd9ca6efeb36336a1f88fb709139ba9 Mon Sep 17 00:00:00 2001 From: Eyal Kapon Date: Mon, 24 Nov 2025 18:18:20 +0200 Subject: [PATCH 28/28] Revert "Optimize build: replace jf go build with regular go build" This reverts commit edfd4252fd904e456b95b1a79bd03712cd664931. --- .github/workflows/release.yml | 9 --------- release/buildAndUpload.sh | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 358120b0b..2897d5e1d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -162,15 +162,6 @@ jobs: git push origin v3 --force echo "Updated v3 tag to ${{ steps.version.outputs.tag }}" - - name: Warm up Go caches for fast parallel builds - run: | - echo "πŸ“¦ Pre-downloading all dependencies..." - go mod download - echo "πŸ”₯ Warming up build cache with quick build..." - go build -o /tmp/frogbot-warmup - rm /tmp/frogbot-warmup - echo "βœ… Caches ready - parallel builds should be blazing fast!" - - name: Build and upload binaries (parallel) env: VERSION: ${{ steps.version.outputs.tag }} diff --git a/release/buildAndUpload.sh b/release/buildAndUpload.sh index a21058874..eb6e1e16f 100755 --- a/release/buildAndUpload.sh +++ b/release/buildAndUpload.sh @@ -9,7 +9,7 @@ build () { exeName="$4" echo "Building $exeName for $GOOS-$GOARCH ..." - CGO_ENABLED=0 go build -o "$exeName" -ldflags '-w -extldflags "-static" -X github.com/jfrog/frogbot/v2/utils.FrogbotVersion='"$version" + CGO_ENABLED=0 jf go build -o "$exeName" -ldflags '-w -extldflags "-static" -X github.com/jfrog/frogbot/v2/utils.FrogbotVersion='"$version" chmod +x "$exeName" # Run verification after building plugin for the correct platform of this image.