fix(shellwrap): capture login-shell PATH for docker credential helpers (#381) #766
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Build | |
| on: | |
| pull_request: | |
| branches: | |
| - "*" | |
| workflow_dispatch: | |
| jobs: | |
| prepare: | |
| name: Prepare Version | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| clean_version: ${{ steps.version.outputs.clean_version }} | |
| latest_tag: ${{ steps.version.outputs.latest_tag }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Generate PR version | |
| id: version | |
| shell: bash | |
| env: | |
| PR_NUMBER: ${{ github.event.number }} | |
| run: | | |
| set -eo pipefail | |
| LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") | |
| COMMIT_HASH=$(git rev-parse --short HEAD) | |
| if [ -n "${PR_NUMBER}" ]; then | |
| VERSION="${LATEST_TAG}-dev-${COMMIT_HASH}-pr${PR_NUMBER}" | |
| else | |
| VERSION="${LATEST_TAG}-dev-${COMMIT_HASH}" | |
| fi | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| echo "clean_version=${VERSION#v}" >> "$GITHUB_OUTPUT" | |
| echo "latest_tag=${LATEST_TAG}" >> "$GITHUB_OUTPUT" | |
| echo "Generated version: ${VERSION}" | |
| verify-oas: | |
| name: Verify OpenAPI Artifacts | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.25" | |
| - name: Install swag | |
| run: go install github.com/swaggo/swag/v2/cmd/swag@v2.0.0-rc4 | |
| - name: Regenerate and verify OpenAPI spec | |
| run: scripts/verify-oas.sh | |
| # Build frontend once and share across all jobs | |
| build-frontend: | |
| name: Build Frontend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install frontend dependencies | |
| run: cd frontend && npm ci | |
| - name: Build frontend | |
| run: cd frontend && npm run build | |
| - name: Upload frontend artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: frontend-dist-pr | |
| path: frontend/dist/ | |
| retention-days: 1 | |
| build: | |
| name: Build Binaries | |
| needs: [prepare, build-frontend, verify-oas] | |
| runs-on: ${{ matrix.os }} | |
| env: | |
| VERSION: ${{ needs.prepare.outputs.version }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| goos: linux | |
| goarch: amd64 | |
| cgo: "0" | |
| name: mcpproxy-linux-amd64 | |
| archive_format: tar.gz | |
| - os: ubuntu-latest | |
| goos: linux | |
| goarch: arm64 | |
| cgo: "0" | |
| name: mcpproxy-linux-arm64 | |
| archive_format: tar.gz | |
| - os: windows-latest | |
| goos: windows | |
| goarch: amd64 | |
| cgo: "1" | |
| name: mcpproxy-windows-amd64.exe | |
| archive_format: zip | |
| - os: windows-latest | |
| goos: windows | |
| goarch: arm64 | |
| cgo: "1" | |
| name: mcpproxy-windows-arm64.exe | |
| archive_format: zip | |
| - os: macos-15 | |
| goos: darwin | |
| goarch: amd64 | |
| cgo: "1" | |
| name: mcpproxy-darwin-amd64 | |
| archive_format: tar.gz | |
| - os: macos-15 | |
| goos: darwin | |
| goarch: arm64 | |
| cgo: "1" | |
| name: mcpproxy-darwin-arm64 | |
| archive_format: tar.gz | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.25" | |
| cache: false # Disable built-in cache to use explicit cache step below | |
| - name: Clean Go module cache (macOS workaround) | |
| if: runner.os == 'macOS' | |
| run: | | |
| # Remove potentially corrupted toolchain files | |
| rm -rf ~/go/pkg/mod/golang.org/toolchain* || true | |
| - name: Cache Go modules and build | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cache/go-build | |
| ~/go/pkg/mod | |
| ~/AppData/Local/go-build | |
| key: ${{ runner.os }}-go-1.25-${{ hashFiles('**/go.sum') }} | |
| restore-keys: | | |
| ${{ runner.os }}-go-1.25- | |
| - name: Download dependencies | |
| run: go mod download | |
| - name: Download frontend artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: frontend-dist-pr | |
| path: frontend/dist | |
| - name: Copy frontend dist for embedding | |
| shell: bash | |
| run: | | |
| rm -rf web/frontend | |
| mkdir -p web/frontend | |
| cp -r frontend/dist web/frontend/ | |
| - name: Run tests (skip binary E2E tests - not compatible with cross-compilation) | |
| # Skip tests for Windows ARM64 (cross-compilation - can't run ARM64 binaries on AMD64 runner) | |
| if: '!(matrix.goos == ''windows'' && matrix.goarch == ''arm64'')' | |
| shell: bash | |
| run: | | |
| # On Windows, skip internal/server tests (E2E tests timeout after 11 minutes) | |
| if [ "${{ matrix.goos }}" = "windows" ]; then | |
| go test -tags nogui -v -skip "E2E|Binary|MCPProtocol" $(go list ./... | grep -v 'internal/server$') | |
| else | |
| go test -tags nogui -v -skip "E2E|Binary|MCPProtocol" ./... | |
| fi | |
| - name: Build binary and create archives | |
| shell: bash | |
| env: | |
| CGO_ENABLED: ${{ matrix.cgo }} | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| VERSION: ${{ env.VERSION }} | |
| # ✅ Force minimum supported macOS version for compatibility (13.0 for Swift tray app) | |
| MACOSX_DEPLOYMENT_TARGET: "13.0" | |
| # Defensive CGO flags to ensure proper deployment target | |
| CGO_CFLAGS: "-mmacosx-version-min=13.0" | |
| CGO_LDFLAGS: "-mmacosx-version-min=13.0" | |
| run: | | |
| LDFLAGS="-s -w -X mcpproxy-go/cmd/mcpproxy.version=${VERSION} -X main.version=${VERSION}" | |
| # Determine clean binary name | |
| if [ "${{ matrix.goos }}" = "windows" ]; then | |
| CLEAN_BINARY="mcpproxy.exe" | |
| else | |
| CLEAN_BINARY="mcpproxy" | |
| fi | |
| # Create clean core binary for archive | |
| go build -ldflags "${LDFLAGS}" -o ${CLEAN_BINARY} ./cmd/mcpproxy | |
| # Build tray binary for platforms with GUI support (macOS and Windows) | |
| if [ "${{ matrix.goos }}" = "darwin" ] || [ "${{ matrix.goos }}" = "windows" ]; then | |
| echo "Building mcpproxy-tray for ${{ matrix.goos }}..." | |
| # Determine tray binary name | |
| if [ "${{ matrix.goos }}" = "windows" ]; then | |
| TRAY_BINARY="mcpproxy-tray.exe" | |
| else | |
| TRAY_BINARY="mcpproxy-tray" | |
| fi | |
| go build -ldflags "${LDFLAGS}" -o ${TRAY_BINARY} ./cmd/mcpproxy-tray | |
| fi | |
| # Ad-hoc sign macOS binaries (development only) | |
| if [ "${{ matrix.goos }}" = "darwin" ]; then | |
| echo "Ad-hoc signing macOS binaries for development..." | |
| codesign --force --deep --sign - --identifier "com.smartmcpproxy.mcpproxy.dev" ${CLEAN_BINARY} | |
| codesign --force --deep --sign - --identifier "com.smartmcpproxy.mcpproxy-tray.dev" mcpproxy-tray | |
| # Verify signing | |
| codesign --verify --verbose ${CLEAN_BINARY} | |
| codesign --verify --verbose mcpproxy-tray | |
| echo "Binaries signed successfully (development)" | |
| fi | |
| # Create archive with version info | |
| ARCHIVE_BASE="mcpproxy-${VERSION#v}-${{ matrix.goos }}-${{ matrix.goarch }}" | |
| # Determine files to include in archive | |
| FILES_TO_ARCHIVE="${CLEAN_BINARY}" | |
| # Add tray binary if it exists (Windows and macOS) | |
| if [ "${{ matrix.goos }}" = "windows" ] && [ -f "mcpproxy-tray.exe" ]; then | |
| FILES_TO_ARCHIVE="${FILES_TO_ARCHIVE} mcpproxy-tray.exe" | |
| echo "Including mcpproxy-tray.exe in archive" | |
| elif [ "${{ matrix.goos }}" = "darwin" ] && [ -f "mcpproxy-tray" ]; then | |
| FILES_TO_ARCHIVE="${FILES_TO_ARCHIVE} mcpproxy-tray" | |
| echo "Including mcpproxy-tray in archive" | |
| fi | |
| if [ "${{ matrix.archive_format }}" = "zip" ]; then | |
| # Create ZIP archive (Windows) | |
| # Use PowerShell Compress-Archive on Windows since zip command isn't available | |
| if [ "${{ matrix.goos }}" = "windows" ]; then | |
| # Convert space-separated list to comma-separated for PowerShell | |
| PS_FILES=$(echo ${FILES_TO_ARCHIVE} | sed 's/ /,/g') | |
| powershell -Command "Compress-Archive -Path ${PS_FILES} -DestinationPath '${ARCHIVE_BASE}.zip'" | |
| else | |
| zip "${ARCHIVE_BASE}.zip" ${FILES_TO_ARCHIVE} | |
| fi | |
| else | |
| # Create tar.gz archive (Unix) | |
| tar -czf "${ARCHIVE_BASE}.tar.gz" ${FILES_TO_ARCHIVE} | |
| fi | |
| # Build Swift tray app (macOS only) | |
| - name: Build Swift tray app | |
| if: matrix.goos == 'darwin' | |
| run: | | |
| chmod +x scripts/build-swift-app.sh | |
| OUTPUT_DIR="$(pwd)/swift-build" | |
| mkdir -p "$OUTPUT_DIR" | |
| ./scripts/build-swift-app.sh "${{ env.VERSION }}" "${{ matrix.goarch }}" "$OUTPUT_DIR" | |
| SWIFT_APP="$OUTPUT_DIR/MCPProxy.app" | |
| if [ -d "$SWIFT_APP" ]; then | |
| # Ad-hoc sign for development | |
| codesign --force --deep --sign - --identifier "com.smartmcpproxy.mcpproxy.dev" "$SWIFT_APP" | |
| echo "SWIFT_APP_PATH=$SWIFT_APP" >> $GITHUB_ENV | |
| else | |
| echo "❌ Swift app build failed" | |
| exit 1 | |
| fi | |
| - name: Create .icns icon (macOS) | |
| if: matrix.goos == 'darwin' | |
| run: | | |
| chmod +x scripts/create-icns.sh | |
| ./scripts/create-icns.sh | |
| - name: Create app bundle and DMG installer (macOS) | |
| if: matrix.goos == 'darwin' | |
| env: | |
| VERSION: ${{ env.VERSION }} | |
| # Ensure DMG creation also uses correct deployment target | |
| MACOSX_DEPLOYMENT_TARGET: "13.0" | |
| CGO_CFLAGS: "-mmacosx-version-min=13.0" | |
| CGO_LDFLAGS: "-mmacosx-version-min=13.0" | |
| run: | | |
| chmod +x scripts/create-pkg.sh | |
| chmod +x scripts/create-app-dmg.sh | |
| # Set up ad-hoc signing for PR builds | |
| echo "=== Creating app bundle and DMG for PR build (ad-hoc signed) ===" | |
| # Determine binary names | |
| TRAY_BINARY="mcpproxy-tray" | |
| CORE_BINARY="mcpproxy" | |
| # Create app bundle using create-pkg.sh in adhoc mode | |
| # This creates the app bundle but skips PKG creation | |
| export APP_CERT_IDENTITY="" # Empty = ad-hoc signing for app bundle | |
| export PKG_CERT_IDENTITY="adhoc" # Skip PKG creation, just create app bundle | |
| # Create app bundle (prefer Swift app bundle over Go tray binary) | |
| if [ -n "${SWIFT_APP_PATH:-}" ] && [ -d "${SWIFT_APP_PATH:-}" ]; then | |
| echo "Using Swift app bundle: $SWIFT_APP_PATH" | |
| ./scripts/create-pkg.sh "$SWIFT_APP_PATH" ${CORE_BINARY} ${VERSION} ${{ matrix.goarch }} | |
| else | |
| echo "Using Go tray binary: ${TRAY_BINARY}" | |
| ./scripts/create-pkg.sh ${TRAY_BINARY} ${CORE_BINARY} ${VERSION} ${{ matrix.goarch }} | |
| fi | |
| # App bundle is created at pkg_temp/pkg_root/Applications/mcpproxy.app | |
| APP_BUNDLE_PATH="pkg_temp/pkg_root/Applications/mcpproxy.app" | |
| if [ -d "$APP_BUNDLE_PATH" ]; then | |
| echo "✅ App bundle created successfully" | |
| # Create DMG containing the app bundle (with Applications symlink for drag-and-drop) | |
| ./scripts/create-app-dmg.sh "$APP_BUNDLE_PATH" ${VERSION} ${{ matrix.goarch }} | |
| # Clean up temp directory now that DMG is created | |
| rm -rf pkg_temp | |
| echo "✅ Installer DMG created successfully (ad-hoc signed, for testing)" | |
| else | |
| echo "❌ App bundle creation failed" | |
| exit 1 | |
| fi | |
| - name: Skip notarization (PR Build) | |
| if: matrix.goos == 'darwin' | |
| run: | | |
| echo "Skipping notarization for PR build - this is a development build" | |
| echo "Production builds go through full notarization in release workflow" | |
| - name: Upload archive artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: archive-${{ matrix.goos }}-${{ matrix.goarch }} | |
| path: mcpproxy-*-${{ matrix.goos }}-${{ matrix.goarch }}.${{ matrix.archive_format }} | |
| retention-days: 14 | |
| - name: Upload macOS installer DMG | |
| if: matrix.goos == 'darwin' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: installer-dmg-${{ matrix.goos }}-${{ matrix.goarch }} | |
| path: mcpproxy-*-darwin-${{ matrix.goarch }}-installer.dmg | |
| retention-days: 14 | |
| if-no-files-found: warn |