diff --git a/.github/workflows/build.disabled b/.github/workflows/build.disabled deleted file mode 100644 index 23bc6f0..0000000 --- a/.github/workflows/build.disabled +++ /dev/null @@ -1,116 +0,0 @@ -name: Build and Release Electron Forge App -on: - push: - branches: - - main - pull_request: -jobs: - build: - name: Build and Package - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - # - os: ubuntu-latest - # arch: x64 - # - os: ubuntu-latest - # arch: arm64 - - os: windows-latest - arch: x64 - - os: macos-latest - arch: x64 - - os: macos-latest - arch: arm64 - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 22 - cache: 'npm' - architecture: ${{ matrix.arch }} - - name: Install Dependencies - run: npm ci - - name: Setup Miniconda - uses: conda-incubator/setup-miniconda@v3 - with: - auto-activate-base: true - - name: Install conda-lock and conda-pack - shell: bash -l {0} - run: | - conda install -n base -c conda-forge conda-lock conda-pack - - name: Create Packaged Python - shell: bash -l {0} - run: | - conda activate base - npm run create:python-tar - - name: Create Builds - run: npm run make - - name: Find and Rename Windows Executable - if: ${{ matrix.os == 'windows-latest' }} - shell: pwsh - run: | - # Dynamically locate the `setup.exe` file within the `out/make` directory structure - $exePath = Get-ChildItem -Path out/make -Recurse -Filter "*.exe" | Select-Object -First 1 - if (-not $exePath) { - throw "Error: No .exe file was found in the output directory." - } - Write-Host "The found executable is: $exePath" - - # Rename/move the file to a more descriptive name with architecture/OS information - $destinationPath = "${{ matrix.os }}-${{ matrix.arch }}.exe" - Copy-Item -Path $exePath.FullName -Destination $destinationPath - Write-Host "Copied executable to: $destinationPath" - - name: Azure Trusted Signing (Windows Only) - if: ${{ matrix.os == 'windows-latest' }} - uses: azure/trusted-signing-action@v0.5.1 - with: - azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} - azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} - azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} - endpoint: https://eus.codesigning.azure.net/ - trusted-signing-account-name: open-webui - certificate-profile-name: open-webui - # Sign the generated .exe file - files-folder: . - files-folder-filter: exe - - name: Zip Artifacts for macOS/Linux - if: ${{ matrix.os != 'windows-latest' }} - run: | - 7z a -tzip ${{ matrix.os }}-${{ matrix.arch }}.zip ./out/make/* - - name: Upload Artifacts - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.os }}-${{ matrix.arch }} - path: | - ${{ matrix.os }}-${{ matrix.arch }}.exe - ${{ matrix.os }}-${{ matrix.arch }}.zip - release: - needs: build - runs-on: ubuntu-latest - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Get Short SHA - id: slug - run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT - - - name: Download Artifacts - uses: actions/download-artifact@v3 - - - name: Create Release - id: create_release - uses: softprops/action-gh-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: build-${{ steps.slug.outputs.sha8 }} - name: Build ${{ steps.slug.outputs.sha8 }} - draft: false - prerelease: false - files: | - **/*.zip - **/*.exe \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..18fc8da --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,144 @@ +name: Build and Release Electron Forge App +on: + push: + branches: + - main + pull_request: +jobs: + build: + name: Build and Package + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + # - os: ubuntu-latest + # arch: x64 + # - os: ubuntu-latest + # arch: arm64 + # - os: windows-latest + # arch: x64 + # - os: macos-latest + # arch: x64 + - os: macos-latest + arch: arm64 + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 22 + cache: 'npm' + architecture: ${{ matrix.arch }} + - name: Install Dependencies + run: npm ci + - name: Setup Miniconda + uses: conda-incubator/setup-miniconda@v3 + with: + auto-activate-base: true + - name: Install conda-lock and conda-pack + shell: bash -l {0} + run: | + conda install -n base -c conda-forge conda-lock conda-pack + - name: Create Packaged Python + shell: bash -l {0} + run: | + conda activate base + npm run create:python-tar + + - name: Install Apple codesigning certificate + if: ${{ matrix.os == 'macos-latest' }} + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + # import certificate and provisioning profile from secrets + echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH + + # create temporary keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + - name: Create Builds + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + CSC_LINK: ${{ secrets.CSC_LINK }} + run: npm run make + - name: Find and Rename Windows Executable + if: ${{ matrix.os == 'windows-latest' }} + shell: pwsh + run: | + # Dynamically locate the `setup.exe` file within the `out/make` directory structure + $exePath = Get-ChildItem -Path out/make -Recurse -Filter "*.exe" | Select-Object -First 1 + if (-not $exePath) { + throw "Error: No .exe file was found in the output directory." + } + Write-Host "The found executable is: $exePath" + + # Rename/move the file to a more descriptive name with architecture/OS information + $destinationPath = "${{ matrix.os }}-${{ matrix.arch }}.exe" + Copy-Item -Path $exePath.FullName -Destination $destinationPath + Write-Host "Copied executable to: $destinationPath" + - name: Azure Trusted Signing (Windows Only) + if: ${{ matrix.os == 'windows-latest' }} + uses: azure/trusted-signing-action@v0.5.1 + with: + azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} + azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} + azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + endpoint: https://eus.codesigning.azure.net/ + trusted-signing-account-name: open-webui + certificate-profile-name: open-webui + # Sign the generated .exe file + files-folder: . + files-folder-filter: exe + - name: Zip Artifacts for macOS/Linux + if: ${{ matrix.os != 'windows-latest' }} + run: | + 7z a -tzip ${{ matrix.os }}-${{ matrix.arch }}.zip ./out/make/* + - name: Upload Artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.os }}-${{ matrix.arch }} + path: | + ${{ matrix.os }}-${{ matrix.arch }}.exe + ${{ matrix.os }}-${{ matrix.arch }}.zip + release: + needs: build + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Get Short SHA + id: slug + run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT + + - name: Download Artifacts + uses: actions/download-artifact@v3 + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: build-${{ steps.slug.outputs.sha8 }} + name: Build ${{ steps.slug.outputs.sha8 }} + draft: false + prerelease: false + files: | + **/*.zip + **/*.exe diff --git a/entitlements.plist b/entitlements.plist new file mode 100644 index 0000000..58b5bae --- /dev/null +++ b/entitlements.plist @@ -0,0 +1,40 @@ + + + + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.debugger + + com.apple.security.network.client + + com.apple.security.network.server + + com.apple.security.files.user-selected.read-only + + com.apple.security.inherit + + com.apple.security.automation.apple-events + + com.apple.security.device.audio-input + + com.apple.security.device.bluetooth + + com.apple.security.device.camera + + com.apple.security.device.print + + com.apple.security.device.microphone + + com.apple.security.device.usb + + com.apple.security.personal-information.location + + + diff --git a/forge.config.ts b/forge.config.ts index e03a8c7..b1d6065 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -12,10 +12,27 @@ const config: ForgeConfig = { executableName: 'open-webui', asar: true, icon: 'public/assets/icon.png', - extraResource: ['public/assets', 'resources'] + extraResource: ['public/assets', 'resources'], + osxSign: { + optionsForFile: (filePath) => { + return { + entitlements: 'entitlements.plist' + }; + } + }, + osxNotarize: { + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLE_PASSWORD, + teamId: process.env.APPLE_TEAM_ID + } }, rebuildConfig: {}, - makers: [new MakerSquirrel({}), new MakerZIP({}, ['darwin']), new MakerRpm({}), new MakerDeb({})], + makers: [ + new MakerSquirrel({}), + new MakerZIP({}, ['darwin']), + new MakerRpm({}), + new MakerDeb({}) + ], plugins: [ new VitePlugin({ // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.