Rebuild aimlapi v0.0.9 with the required manifest fields #2
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: Pre Check Plugin | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review] | |
| branches: | |
| - main | |
| - dev | |
| paths-ignore: | |
| - ".github/**" | |
| - ".gitignore" | |
| - "**/.gitignore" | |
| - "unpacked_plugin/**" | |
| - "**/*.md" | |
| - "LICENSE" | |
| concurrency: | |
| group: pre-check-plugin-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| env: | |
| REPO_NAME: langgenius/dify-plugins | |
| MARKETPLACE_BASE_URL: https://marketplace.dify.ai | |
| MARKETPLACE_TOKEN: placeholder | |
| GH_TOKEN: ${{ github.token }} | |
| jobs: | |
| pre-check-plugin: | |
| runs-on: depot-ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 2 | |
| - name: Clone Marketplace Toolkit | |
| run: | | |
| gh repo clone langgenius/dify-marketplace-toolkit -- .scripts/ | |
| - name: Download Plugin Daemon | |
| run: | | |
| gh release download -R langgenius/dify-plugin-daemon --pattern "dify-plugin-linux-amd64" --dir .scripts | |
| chmod +x .scripts/dify-plugin-linux-amd64 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: 3.12.7 | |
| - name: Install Dependencies | |
| run: | | |
| echo "Installing Python dependencies..." | |
| pip install requests | |
| # Remaining packages are only needed by "Check Plugin Deps"; | |
| # install in the background (the rest is preinstalled on the image). | |
| echo "Installing system dependencies in the background..." | |
| sudo rm -f /var/lib/man-db/auto-update # skip slow man-db trigger | |
| sudo bash -c ' | |
| set -e | |
| export DEBIAN_FRONTEND=noninteractive | |
| # default EC2 apt mirror stalls; use the main archive | |
| if [ -f /etc/apt/apt-mirrors.txt ]; then | |
| echo "http://archive.ubuntu.com/ubuntu/" > /etc/apt/apt-mirrors.txt | |
| fi | |
| APT_OPTS="-o Acquire::Retries=3 -o Acquire::http::Timeout=15 -o Acquire::https::Timeout=15" | |
| apt-get update -q $APT_OPTS | |
| apt-get install -y -q --no-install-recommends $APT_OPTS \ | |
| ffmpeg \ | |
| libcairo2-dev libjpeg-dev libgif-dev | |
| touch /tmp/apt-deps-ok | |
| ' </dev/null >/tmp/apt-deps.log 2>&1 & | |
| echo "APT_DEPS_PID=$!" >> "$GITHUB_ENV" | |
| - name: Verify Preinstalled Tools | |
| run: | | |
| jq --version | |
| yq --version | |
| - name: Get PR Path | |
| run: | | |
| echo "Retrieving PR files information..." | |
| if ! PR_FILES=$(gh pr view -R ${{ env.REPO_NAME }} ${{ github.event.pull_request.number }} --json files --jq .files); then | |
| echo "Failed to retrieve PR files. Make sure PR number and repository are correct." | |
| exit 1 | |
| fi | |
| gh pr view -R ${{ env.REPO_NAME }} ${{ github.event.pull_request.number }} --json body --jq .body > /tmp/pr_body.md | |
| export PR_FILES | |
| echo "Checking for plugin package file changes..." | |
| if PLUGIN_PATH=$(python3 .scripts/validator/check-pkg-paths.py); then | |
| echo "Found plugin path: $PLUGIN_PATH" | |
| echo "PLUGIN_PATH=$PLUGIN_PATH" >> $GITHUB_ENV | |
| echo "SUBMITTED_PLUGIN_PATH=$PLUGIN_PATH" >> $GITHUB_ENV | |
| else | |
| echo "ERROR: Only one .difypkg file change is allowed in a single PR." | |
| exit 1 | |
| fi | |
| - name: Unpack File | |
| run: | | |
| # Store the plugin path in a variable | |
| PLUGIN_PATH_VALUE="${PLUGIN_PATH}" | |
| echo "Moving plugin file to add .zip extension" | |
| mv "$PLUGIN_PATH_VALUE" "$PLUGIN_PATH_VALUE.zip" | |
| echo "Creating unpacked_plugin directory" | |
| mkdir -p unpacked_plugin | |
| echo "Unzipping plugin file to unpacked_plugin directory" | |
| unzip "$PLUGIN_PATH_VALUE.zip" -d unpacked_plugin | |
| # Update the PLUGIN_PATH for future steps | |
| echo "PLUGIN_PATH=unpacked_plugin" >> $GITHUB_ENV | |
| - name: Check Package Contents | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-package-contents.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --package-file "$SUBMITTED_PLUGIN_PATH.zip" \ | |
| --error-file /tmp/package_contents_errors.txt \ | |
| --warning-file /tmp/package_contents_warnings.txt | |
| - name: Check Package Secrets | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-package-secrets.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --error-file /tmp/package_secrets_errors.txt \ | |
| --warning-file /tmp/package_secrets_warnings.txt | |
| - name: Check Package Binaries | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-package-binaries.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --error-file /tmp/package_binaries_errors.txt \ | |
| --warning-file /tmp/package_binaries_warnings.txt | |
| - name: Check Plugin Manifest | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-manifest-metadata.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --error-file /tmp/manifest_errors.txt \ | |
| --warning-file /tmp/manifest_warnings.txt | |
| - name: Check README Metadata | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-readme-metadata.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --error-file /tmp/readme_errors.txt \ | |
| --warning-file /tmp/readme_warnings.txt | |
| - name: Check PR Body | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-pr-body.py \ | |
| --pr-body-file /tmp/pr_body.md \ | |
| --error-file /tmp/pr_body_errors.txt | |
| - name: Check PR Review Notes | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-pr-review-notes.py \ | |
| --pr-body-file /tmp/pr_body.md \ | |
| --warning-file /tmp/pr_review_notes_warnings.txt | |
| - name: Check Version Update | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-version-update.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --package-path "$SUBMITTED_PLUGIN_PATH.zip" \ | |
| --pr-body-file /tmp/pr_body.md \ | |
| --error-file /tmp/version_update_errors.txt \ | |
| --warning-file /tmp/version_update_warnings.txt | |
| - name: Check Package Dependencies | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-package-dependencies.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --error-file /tmp/package_dependencies_errors.txt \ | |
| --warning-file /tmp/package_dependencies_warnings.txt | |
| - name: Check Sensitive Capability Disclosure | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-sensitive-capabilities.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --pr-body-file /tmp/pr_body.md \ | |
| --error-file /tmp/sensitive_capabilities_errors.txt \ | |
| --warning-file /tmp/sensitive_capabilities_warnings.txt | |
| - name: Check Python Safety Warnings | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-python-safety-warnings.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --warning-file /tmp/python_safety_warnings.txt | |
| - name: Check Prohibited Financial Activity | |
| continue-on-error: true | |
| run: | | |
| python3 .scripts/validator/check-prohibited-financial-activity.py \ | |
| -d "$PLUGIN_PATH" \ | |
| --warning-file /tmp/prohibited_financial_activity_warnings.txt | |
| - name: Check Plugin Icon | |
| continue-on-error: true | |
| run: | | |
| # Create error tracking file | |
| ERROR_FILE="/tmp/icon_errors.txt" | |
| touch $ERROR_FILE | |
| # Get icon filename from manifest.yaml | |
| PLUGIN_ICON_FILENAME=$(yq '.icon' "$PLUGIN_PATH/manifest.yaml") | |
| echo "PLUGIN_ICON_FILENAME=$PLUGIN_ICON_FILENAME" >> $GITHUB_ENV | |
| # Check if icon file exists | |
| if [ ! -f "$PLUGIN_PATH/_assets/$PLUGIN_ICON_FILENAME" ]; then | |
| ERROR_MSG="!!! Plugin icon file not found: _assets/$PLUGIN_ICON_FILENAME" | |
| echo "$ERROR_MSG" | |
| echo "$ERROR_MSG" >> $ERROR_FILE | |
| exit 1 | |
| fi | |
| # Check if icon contains template placeholder text | |
| if grep -q "DIFY_MARKETPLACE_TEMPLATE_ICON_DO_NOT_USE" "$PLUGIN_PATH/_assets/$PLUGIN_ICON_FILENAME"; then | |
| ERROR_MSG="!!! Plugin icon contains template placeholder text 'DIFY_MARKETPLACE_TEMPLATE_ICON_DO_NOT_USE', change default icon before submitting to marketplace." | |
| echo "$ERROR_MSG" | |
| echo "$ERROR_MSG" >> $ERROR_FILE | |
| exit 1 | |
| fi | |
| # Define default icon content | |
| DEFAULT_ICON='<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> | |
| <path d="M20 20 V80 M20 20 H60 Q80 20 80 40 T60 60 H20" | |
| fill="none" | |
| stroke="black" | |
| stroke-width="5"/> | |
| </svg>' | |
| # Check if icon content matches default icon (normalize whitespace) | |
| ICON_CONTENT=$(cat "$PLUGIN_PATH/_assets/$PLUGIN_ICON_FILENAME" | tr -d '\n\r\t ' | tr -s ' ') | |
| DEFAULT_ICON_NORMALIZED=$(echo "$DEFAULT_ICON" | tr -d '\n\r\t ' | tr -s ' ') | |
| if [ "$ICON_CONTENT" = "$DEFAULT_ICON_NORMALIZED" ]; then | |
| ERROR_MSG="!!! Plugin icon is using the default template icon and must be customized" | |
| echo "$ERROR_MSG" | |
| echo "$ERROR_MSG" >> $ERROR_FILE | |
| exit 1 | |
| fi | |
| - name: Check If Version Exists | |
| continue-on-error: true | |
| run: | | |
| # Create error tracking file | |
| ERROR_FILE="/tmp/version_errors.txt" | |
| touch $ERROR_FILE | |
| # Extract plugin metadata | |
| VERSION=$(yq '.version' "$PLUGIN_PATH/manifest.yaml") | |
| AUTHOR=$(yq '.author' "$PLUGIN_PATH/manifest.yaml") | |
| NAME=$(yq '.name' "$PLUGIN_PATH/manifest.yaml") | |
| echo "Plugin information:" | |
| echo "- Name: $NAME" | |
| echo "- Author: $AUTHOR" | |
| echo "- Version: $VERSION" | |
| # Check if the version already exists in marketplace | |
| echo "Checking if plugin version already exists in marketplace..." | |
| API_URL="${MARKETPLACE_BASE_URL}/api/v1/plugins/${AUTHOR}/${NAME}/${VERSION}" | |
| echo "API URL: $API_URL" | |
| # Add a timeout to curl to prevent hanging | |
| RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$API_URL" --connect-timeout 10 --max-time 30) | |
| echo "API Response Code: $RESPONSE_CODE" | |
| if [ "$RESPONSE_CODE" = "200" ]; then | |
| RESPONSE=$(curl -s "$API_URL" --connect-timeout 10 --max-time 30) | |
| if [ "$(echo "$RESPONSE" | jq -r '.code')" = "0" ]; then | |
| ERROR_MSG="!!! Plugin version $VERSION by $AUTHOR already exists in the marketplace. Please update the version number in manifest.yaml before submitting." | |
| echo "$ERROR_MSG" | |
| echo "$ERROR_MSG" >> $ERROR_FILE | |
| exit 1 | |
| fi | |
| else | |
| echo "Version check passed: $VERSION is available for use." | |
| fi | |
| - name: Wait for System Dependencies | |
| timeout-minutes: 10 | |
| run: | | |
| echo "Waiting for background apt install (pid ${APT_DEPS_PID:-unknown})..." | |
| if [ -n "${APT_DEPS_PID:-}" ]; then | |
| tail --pid="$APT_DEPS_PID" -f /dev/null || true | |
| fi | |
| if [ ! -f /tmp/apt-deps-ok ]; then | |
| echo "System dependency installation failed:" | |
| cat /tmp/apt-deps.log | |
| exit 1 | |
| fi | |
| echo "System dependencies ready." | |
| - name: Check Plugin Deps | |
| continue-on-error: true | |
| run: | | |
| ERROR_FILE="/tmp/install_errors.txt" | |
| touch $ERROR_FILE | |
| if [ -f "$PLUGIN_PATH/requirements.txt" ]; then | |
| echo "Trying to install plugin dependencies..." | |
| python3 -m venv .venv | |
| source .venv/bin/activate | |
| python3 -m pip install -r "$PLUGIN_PATH/requirements.txt" || { | |
| echo "Failed to install plugin dependencies" >> $ERROR_FILE | |
| echo "Failed to install plugin dependencies" | |
| exit 1 | |
| } | |
| deactivate | |
| else | |
| echo "No requirements.txt found, skipping dependency installation" | |
| fi | |
| - name: Check Plugin Install | |
| continue-on-error: true | |
| run: | | |
| # Create error tracking file | |
| ERROR_FILE="/tmp/install_errors.txt" | |
| touch $ERROR_FILE | |
| if [ -f "$PLUGIN_PATH/requirements.txt" ]; then | |
| source .venv/bin/activate || { | |
| echo "Failed to activate virtual environment" >> $ERROR_FILE | |
| echo "Failed to activate virtual environment" | |
| exit 1 | |
| } | |
| # Install packaging for version comparison | |
| echo "Installing packaging module..." | |
| pip install packaging || { | |
| echo "Failed to install packaging module" >> $ERROR_FILE | |
| echo "Failed to install packaging module" | |
| exit 1 | |
| } | |
| # Determine installation method based on dify_plugin version | |
| echo "Detecting dify_plugin version..." | |
| dify_version=$(pip list | grep -oE 'dify[-_]plugin[[:space:]]+[0-9][0-9.a-zA-Z]*' | awk '{print $2}') | |
| if [ -z "$dify_version" ]; then | |
| dify_version="not_found" | |
| fi | |
| if [ "$dify_version" = "not_found" ]; then | |
| echo "dify_plugin not found in installed packages, using default configuration" | |
| export INSTALL_METHOD=aws_lambda | |
| export AWS_LAMBDA_PORT=8080 | |
| export AWS_LAMBDA_HOST=0.0.0.0 | |
| else | |
| target_version="0.0.1b64" | |
| echo "Found dify_plugin version: $dify_version" | |
| echo "Comparing with target version: $target_version" | |
| # Set environment variables based on version comparison | |
| if python -c "from packaging.version import Version; exit(0 if Version('$dify_version') > Version('$target_version') else 1)"; then | |
| echo "Using serverless installation method" | |
| export INSTALL_METHOD=serverless | |
| export SERVERLESS_PORT=8080 | |
| export SERVERLESS_HOST=0.0.0.0 | |
| else | |
| echo "Using aws_lambda installation method" | |
| export INSTALL_METHOD=aws_lambda | |
| export AWS_LAMBDA_PORT=8080 | |
| export AWS_LAMBDA_HOST=0.0.0.0 | |
| fi | |
| fi | |
| # Run the plugin installation test with timeout | |
| echo "Running plugin installation test..." | |
| timeout 300 python3 .scripts/validator/test-plugin-install.py -d "$PLUGIN_PATH" || { | |
| echo "Plugin installation test failed or timed out" >> $ERROR_FILE | |
| echo "Plugin installation test failed or timed out" | |
| exit 1 | |
| } | |
| echo "Plugin installation test completed successfully" | |
| else | |
| echo "No requirements.txt found, skipping installation test" | |
| fi | |
| - name: Check Packaging | |
| continue-on-error: true | |
| run: | | |
| # Create error tracking file | |
| ERROR_FILE="/tmp/packaging_errors.txt" | |
| touch $ERROR_FILE | |
| echo "Running packaging check..." | |
| # Check if plugin daemon exists (executable bit set at download time) | |
| if [ ! -x ".scripts/dify-plugin-linux-amd64" ]; then | |
| ERROR_MSG="Plugin daemon file not found or not executable" | |
| echo "$ERROR_MSG" >> $ERROR_FILE | |
| echo "$ERROR_MSG" | |
| exit 1 | |
| fi | |
| # Run the packaging check with a timeout | |
| timeout 300 python3 .scripts/uploader -d "$PLUGIN_PATH" -t "$MARKETPLACE_TOKEN" --plugin-daemon-path .scripts/dify-plugin-linux-amd64 -u "$MARKETPLACE_BASE_URL" -f --test || { | |
| ERROR_MSG="Packaging check failed or timed out" | |
| echo "$ERROR_MSG" >> $ERROR_FILE | |
| echo "$ERROR_MSG" | |
| exit 1 | |
| } | |
| echo "Packaging check completed successfully" | |
| - name: Output Detailed Report (Step Summary) | |
| if: always() | |
| run: | | |
| SUMMARY_FILE="${GITHUB_STEP_SUMMARY:-/tmp/github_step_summary.md}" | |
| JOB_STATUS="${{ job.status }}" | |
| echo "# Plugin Pre-Check Report" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "## Plugin Information" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| if [ -n "${PLUGIN_PATH:-}" ] && [ -f "$PLUGIN_PATH/manifest.yaml" ]; then | |
| PLUGIN_NAME=$(yq '.name // "Unknown"' "$PLUGIN_PATH/manifest.yaml" 2>/dev/null || echo "Unknown") | |
| PLUGIN_VERSION=$(yq '.version // "Unknown"' "$PLUGIN_PATH/manifest.yaml" 2>/dev/null || echo "Unknown") | |
| PLUGIN_AUTHOR=$(yq '.author // "Unknown"' "$PLUGIN_PATH/manifest.yaml" 2>/dev/null || echo "Unknown") | |
| PLUGIN_DESCRIPTION=$(yq '.description // "No description provided"' "$PLUGIN_PATH/manifest.yaml" 2>/dev/null || echo "No description provided") | |
| echo "- **Name:** $PLUGIN_NAME" >> "$SUMMARY_FILE" | |
| echo "- **Version:** $PLUGIN_VERSION" >> "$SUMMARY_FILE" | |
| echo "- **Author:** $PLUGIN_AUTHOR" >> "$SUMMARY_FILE" | |
| echo "- **Description:** $PLUGIN_DESCRIPTION" >> "$SUMMARY_FILE" | |
| else | |
| if [ -z "${PLUGIN_PATH:-}" ]; then | |
| echo "- ⚠️ \`PLUGIN_PATH\` is not set (plugin package may not have been detected/unpacked)." >> "$SUMMARY_FILE" | |
| else | |
| echo "- ⚠️ \`manifest.yaml\` not found under \`$PLUGIN_PATH\`." >> "$SUMMARY_FILE" | |
| fi | |
| fi | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "## CI Steps Status" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "| Check | Status |" >> "$SUMMARY_FILE" | |
| echo "| ----- | ------ |" >> "$SUMMARY_FILE" | |
| case "$JOB_STATUS" in | |
| success) echo "| **Overall Status** | ✅ **Passed** |" >> "$SUMMARY_FILE" ;; | |
| cancelled) echo "| **Overall Status** | ⚠️ **Cancelled** |" >> "$SUMMARY_FILE" ;; | |
| *) echo "| **Overall Status** | ❌ **Failed** |" >> "$SUMMARY_FILE" ;; | |
| esac | |
| if [ -f "/tmp/manifest_errors.txt" ] && [ -s "/tmp/manifest_errors.txt" ]; then | |
| echo "| **Manifest Validation** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -f "/tmp/manifest_warnings.txt" ] && [ -s "/tmp/manifest_warnings.txt" ]; then | |
| echo "| **Manifest Validation** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Manifest Validation** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/readme_errors.txt" ] && [ -s "/tmp/readme_errors.txt" ]; then | |
| echo "| **README Metadata** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -f "/tmp/readme_warnings.txt" ] && [ -s "/tmp/readme_warnings.txt" ]; then | |
| echo "| **README Metadata** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **README Metadata** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/pr_body_errors.txt" ] && [ -s "/tmp/pr_body_errors.txt" ]; then | |
| echo "| **PR Body** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **PR Body** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/pr_review_notes_warnings.txt" ] && [ -s "/tmp/pr_review_notes_warnings.txt" ]; then | |
| echo "| **PR Review Notes** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **PR Review Notes** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/icon_errors.txt" ] && [ -s "/tmp/icon_errors.txt" ]; then | |
| echo "| **Icon Validation** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Icon Validation** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/version_errors.txt" ] && [ -s "/tmp/version_errors.txt" ]; then | |
| echo "| **Version Check** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Version Check** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/version_update_errors.txt" ] && [ -s "/tmp/version_update_errors.txt" ]; then | |
| echo "| **Version Update Increment** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -f "/tmp/version_update_warnings.txt" ] && [ -s "/tmp/version_update_warnings.txt" ]; then | |
| echo "| **Version Update Increment** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Version Update Increment** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/package_contents_errors.txt" ] && [ -s "/tmp/package_contents_errors.txt" ]; then | |
| echo "| **Package Contents** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -f "/tmp/package_contents_warnings.txt" ] && [ -s "/tmp/package_contents_warnings.txt" ]; then | |
| echo "| **Package Contents** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Package Contents** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/package_secrets_errors.txt" ] && [ -s "/tmp/package_secrets_errors.txt" ]; then | |
| echo "| **Package Secrets** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -f "/tmp/package_secrets_warnings.txt" ] && [ -s "/tmp/package_secrets_warnings.txt" ]; then | |
| echo "| **Package Secrets** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Package Secrets** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/package_binaries_errors.txt" ] && [ -s "/tmp/package_binaries_errors.txt" ]; then | |
| echo "| **Package Binaries** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -f "/tmp/package_binaries_warnings.txt" ] && [ -s "/tmp/package_binaries_warnings.txt" ]; then | |
| echo "| **Package Binaries** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Package Binaries** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/package_dependencies_errors.txt" ] && [ -s "/tmp/package_dependencies_errors.txt" ]; then | |
| echo "| **Package Dependencies** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -f "/tmp/package_dependencies_warnings.txt" ] && [ -s "/tmp/package_dependencies_warnings.txt" ]; then | |
| echo "| **Package Dependencies** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Package Dependencies** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/sensitive_capabilities_errors.txt" ] && [ -s "/tmp/sensitive_capabilities_errors.txt" ]; then | |
| echo "| **Sensitive Capability Disclosure** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -f "/tmp/sensitive_capabilities_warnings.txt" ] && [ -s "/tmp/sensitive_capabilities_warnings.txt" ]; then | |
| echo "| **Sensitive Capability Disclosure** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Sensitive Capability Disclosure** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/python_safety_warnings.txt" ] && [ -s "/tmp/python_safety_warnings.txt" ]; then | |
| echo "| **Python Safety Warnings** | ⚠️ Review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Python Safety Warnings** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/prohibited_financial_activity_warnings.txt" ] && [ -s "/tmp/prohibited_financial_activity_warnings.txt" ]; then | |
| echo "| **Prohibited Financial Activity** | ⚠️ Strong manual review required |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Prohibited Financial Activity** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/install_errors.txt" ] && [ -s "/tmp/install_errors.txt" ]; then | |
| echo "| **Installation** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| elif [ -n "${PLUGIN_PATH:-}" ] && [ -f "$PLUGIN_PATH/requirements.txt" ]; then | |
| echo "| **Installation** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Installation** | ⚠️ Skipped |" >> "$SUMMARY_FILE" | |
| fi | |
| if [ -f "/tmp/packaging_errors.txt" ] && [ -s "/tmp/packaging_errors.txt" ]; then | |
| echo "| **Packaging** | ❌ Failed |" >> "$SUMMARY_FILE" | |
| else | |
| echo "| **Packaging** | ✅ Passed |" >> "$SUMMARY_FILE" | |
| fi | |
| escape_html() { | |
| sed -e 's/&/&/g' -e 's/</</g' -e 's/>/>/g' | |
| } | |
| append_error_details() { | |
| local title="$1" | |
| local file="$2" | |
| if [ -f "$file" ] && [ -s "$file" ]; then | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "<details>" >> "$SUMMARY_FILE" | |
| echo "<summary>${title} (details)</summary>" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "<pre><code class=\"language-text\">" >> "$SUMMARY_FILE" | |
| escape_html < "$file" >> "$SUMMARY_FILE" | |
| echo "</code></pre>" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "</details>" >> "$SUMMARY_FILE" | |
| fi | |
| } | |
| append_grouped_report() { | |
| local title="$1" | |
| shift | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "## ${title}" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| local found=0 | |
| for file in "$@"; do | |
| if [ -f "$file" ] && [ -s "$file" ]; then | |
| found=1 | |
| echo "- \`$file\`" >> "$SUMMARY_FILE" | |
| fi | |
| done | |
| if [ "$found" = "0" ]; then | |
| echo "_None._" >> "$SUMMARY_FILE" | |
| fi | |
| } | |
| append_grouped_report "Blocking Errors" \ | |
| "/tmp/manifest_errors.txt" \ | |
| "/tmp/readme_errors.txt" \ | |
| "/tmp/pr_body_errors.txt" \ | |
| "/tmp/icon_errors.txt" \ | |
| "/tmp/version_errors.txt" \ | |
| "/tmp/version_update_errors.txt" \ | |
| "/tmp/package_contents_errors.txt" \ | |
| "/tmp/package_secrets_errors.txt" \ | |
| "/tmp/package_binaries_errors.txt" \ | |
| "/tmp/package_dependencies_errors.txt" \ | |
| "/tmp/sensitive_capabilities_errors.txt" \ | |
| "/tmp/install_errors.txt" \ | |
| "/tmp/packaging_errors.txt" | |
| append_grouped_report "Warnings" \ | |
| "/tmp/manifest_warnings.txt" \ | |
| "/tmp/readme_warnings.txt" \ | |
| "/tmp/pr_review_notes_warnings.txt" \ | |
| "/tmp/version_update_warnings.txt" \ | |
| "/tmp/package_contents_warnings.txt" \ | |
| "/tmp/package_secrets_warnings.txt" \ | |
| "/tmp/package_binaries_warnings.txt" \ | |
| "/tmp/package_dependencies_warnings.txt" \ | |
| "/tmp/sensitive_capabilities_warnings.txt" \ | |
| "/tmp/python_safety_warnings.txt" \ | |
| "/tmp/prohibited_financial_activity_warnings.txt" | |
| append_error_details "Manifest Validation" "/tmp/manifest_errors.txt" | |
| append_error_details "Manifest Warnings" "/tmp/manifest_warnings.txt" | |
| append_error_details "README Metadata" "/tmp/readme_errors.txt" | |
| append_error_details "README Warnings" "/tmp/readme_warnings.txt" | |
| append_error_details "PR Body" "/tmp/pr_body_errors.txt" | |
| append_error_details "PR Review Notes Warnings" "/tmp/pr_review_notes_warnings.txt" | |
| append_error_details "Icon Validation" "/tmp/icon_errors.txt" | |
| append_error_details "Version Check" "/tmp/version_errors.txt" | |
| append_error_details "Version Update Errors" "/tmp/version_update_errors.txt" | |
| append_error_details "Version Update Warnings" "/tmp/version_update_warnings.txt" | |
| append_error_details "Package Contents Errors" "/tmp/package_contents_errors.txt" | |
| append_error_details "Package Contents Warnings" "/tmp/package_contents_warnings.txt" | |
| append_error_details "Package Secrets Errors" "/tmp/package_secrets_errors.txt" | |
| append_error_details "Package Secrets Warnings" "/tmp/package_secrets_warnings.txt" | |
| append_error_details "Package Binaries Errors" "/tmp/package_binaries_errors.txt" | |
| append_error_details "Package Binaries Warnings" "/tmp/package_binaries_warnings.txt" | |
| append_error_details "Package Dependencies Errors" "/tmp/package_dependencies_errors.txt" | |
| append_error_details "Package Dependencies Warnings" "/tmp/package_dependencies_warnings.txt" | |
| append_error_details "Sensitive Capability Disclosure Errors" "/tmp/sensitive_capabilities_errors.txt" | |
| append_error_details "Sensitive Capability Disclosure Warnings" "/tmp/sensitive_capabilities_warnings.txt" | |
| append_error_details "Python Safety Warnings" "/tmp/python_safety_warnings.txt" | |
| append_error_details "Prohibited Financial Activity Warnings" "/tmp/prohibited_financial_activity_warnings.txt" | |
| append_error_details "Installation" "/tmp/install_errors.txt" | |
| append_error_details "Packaging" "/tmp/packaging_errors.txt" | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "## Plugin Files" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| append_file_content() { | |
| local title="$1" | |
| local file="$2" | |
| local language="${3:-text}" | |
| echo "<details>" >> "$SUMMARY_FILE" | |
| echo "<summary>${title}</summary>" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| if [ -n "$file" ] && [ -f "$file" ]; then | |
| echo "<pre><code class=\"language-${language}\">" >> "$SUMMARY_FILE" | |
| escape_html < "$file" >> "$SUMMARY_FILE" | |
| echo "</code></pre>" >> "$SUMMARY_FILE" | |
| else | |
| echo "_Not found: \`$file\`_" >> "$SUMMARY_FILE" | |
| fi | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "</details>" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| } | |
| if [ -n "${PLUGIN_PATH:-}" ]; then | |
| append_file_content "manifest.yaml" "$PLUGIN_PATH/manifest.yaml" "yaml" | |
| append_file_content "README.md" "$PLUGIN_PATH/README.md" "markdown" | |
| append_file_content "PRIVACY.md" "$PLUGIN_PATH/PRIVACY.md" "markdown" | |
| append_file_content "requirements.txt" "$PLUGIN_PATH/requirements.txt" "text" | |
| append_file_content "pyproject.toml" "$PLUGIN_PATH/pyproject.toml" "toml" | |
| else | |
| echo "_Plugin directory is unavailable (missing \`PLUGIN_PATH\`)._" >> "$SUMMARY_FILE" | |
| fi | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "## Workflow Details" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "- **Run ID:** ${{ github.run_id }}" >> "$SUMMARY_FILE" | |
| echo "- **Repository:** ${{ github.repository }}" >> "$SUMMARY_FILE" | |
| echo "- **Ref:** ${{ github.ref }}" >> "$SUMMARY_FILE" | |
| echo "" >> "$SUMMARY_FILE" | |
| echo "[View workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> "$SUMMARY_FILE" | |
| - name: Fail on Blocking Errors | |
| if: always() | |
| run: | | |
| BLOCKING_ERROR_FILES=( | |
| /tmp/manifest_errors.txt | |
| /tmp/readme_errors.txt | |
| /tmp/pr_body_errors.txt | |
| /tmp/icon_errors.txt | |
| /tmp/version_errors.txt | |
| /tmp/version_update_errors.txt | |
| /tmp/package_contents_errors.txt | |
| /tmp/package_secrets_errors.txt | |
| /tmp/package_binaries_errors.txt | |
| /tmp/package_dependencies_errors.txt | |
| /tmp/sensitive_capabilities_errors.txt | |
| /tmp/install_errors.txt | |
| /tmp/packaging_errors.txt | |
| ) | |
| HAS_ERRORS=0 | |
| for file in "${BLOCKING_ERROR_FILES[@]}"; do | |
| if [ -f "$file" ] && [ -s "$file" ]; then | |
| echo "Blocking errors found in $file" | |
| HAS_ERRORS=1 | |
| fi | |
| done | |
| if [ "$HAS_ERRORS" = "1" ]; then | |
| echo "One or more blocking plugin checks failed. See the job summary for details." | |
| exit 1 | |
| fi | |
| echo "No blocking plugin check errors found." |