imbajin commented on code in PR #464:
URL: https://github.com/apache/hugegraph-doc/pull/464#discussion_r3733078678


##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+  workflow_dispatch:
+    inputs:
+      release_version:
+        required: true
+        description: svn release version
+        default: '1.7.0'
+      gpg_user:
+        required: true
+        description: current release manager (gpg username)
+        default: 'pengjunzhi'
+      java_version:
+        required: false
+        description: Java version to validate
+        default: '11'
+        type: choice
+        options:
+          - '11'
+          - '17'
+
+  push:
+    branches:
+      - 'release-*'
+  pull_request:
+    branches:
+      - 'release-*'
+
+jobs:
+  validate:
+    name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version 
}})"
+    runs-on: ${{ matrix.os }}
+    env:
+      RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
+      GPG_USER: ${{ inputs.gpg_user || 'pengjunzhi' }}
+      JAVA_VERSION: ${{ inputs.java_version || matrix.java_version || '11' }}
+      SVN_URL_PREFIX: 
https://dist.apache.org/repos/dist/dev/incubator/hugegraph
+      KEYS_URL: https://downloads.apache.org/incubator/hugegraph/KEYS
+      MAX_FILE_SIZE: 800k
+      SERVER_START_DELAY: 3
+      # License Patterns (ASF Category X - Prohibited)
+      CATEGORY_X: '\bGPL|\bLGPL|Sleepycat 
License|BSD-4-Clause|\bBCL\b|JSR-275|Amazon Software 
License|\bRSAL\b|\bQPL\b|\bSSPL|\bCPOL|\bNPL1|Creative Commons 
Non-Commercial|JSON\.org'
+      # License Patterns (ASF Category B - Must be documented)
+      CATEGORY_B: '\bCDDL1|\bCPL|\bEPL|\bIPL|\bMPL|\bSPL|OSL-3.0|UnRAR 
License|Erlang Public License|\bOFL\b|Ubuntu Font License Version 1.0|IPA Font 
License Agreement v1.0|EPL2.0|CC-BY'
+    steps:
+      - name: Checkout source
+        uses: actions/checkout@v4
+
+      - name: Install JDK ${{ env.JAVA_VERSION }}
+        uses: actions/setup-java@v3
+        with:
+          java-version: ${{ env.JAVA_VERSION }}
+          distribution: 'adopt'
+
+      - name: Install dependencies
+        run: |
+          if [[ "${{ runner.os }}" == "macOS" ]]; then
+            brew install svn wget perl
+          elif [[ "${{ runner.os }}" == "Linux" ]]; then
+            sudo apt-get update
+            sudo apt-get install -y subversion wget perl
+          fi
+          # Verify all required commands
+          for cmd in svn gpg shasum mvn java wget tar curl awk grep find perl; 
do
+            if ! command -v "$cmd" &> /dev/null; then
+              echo "Error: Missing required dependency: $cmd"
+              exit 1
+            fi
+            echo "✓ $cmd: $(command -v $cmd)"
+          done
+
+      - name: Cache Maven packages
+        uses: actions/cache@v3
+        with:
+          path: ~/.m2
+          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+          restore-keys: ${{ runner.os }}-m2
+
+      - name: Step 1 - Check Dependencies
+        run: |
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [1/9]: Check Dependencies"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          # Check Java version
+          CURRENT_JAVA=$(java -version 2>&1 | head -n 1 | awk -F '"' '{print 
$2}' | awk -F '.' '{print $1}')
+          echo "Current Java version: $CURRENT_JAVA (Required: ${{ 
env.JAVA_VERSION }})"
+          if [[ "$CURRENT_JAVA" != "${{ env.JAVA_VERSION }}" ]]; then
+            echo "Error: Java version mismatch! Current: Java $CURRENT_JAVA, 
Required: Java ${{ env.JAVA_VERSION }}"
+            exit 1
+          fi
+          echo "✓ Java version check passed: Java $CURRENT_JAVA"
+
+      - name: Step 2 - Prepare Release Files
+        run: |
+          echo ""
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [2/9]: Prepare Release Files"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          DIST_DIR="dist/${{ env.RELEASE_VERSION }}"
+          echo "Downloading from SVN to: ${DIST_DIR}"
+          
+          rm -rf "${DIST_DIR}"
+          mkdir -p "${DIST_DIR}"
+          
+          if ! svn co "${SVN_URL_PREFIX}/${{ env.RELEASE_VERSION }}" 
"${DIST_DIR}"; then
+            echo "Error: Failed to download from SVN: ${SVN_URL_PREFIX}/${{ 
env.RELEASE_VERSION }}"
+            exit 1
+          fi
+          
+          echo "✓ Downloaded release files from SVN"
+          cd "${DIST_DIR}"
+          ls -lh
+
+      - name: Step 3 - Import & Trust GPG Keys
+        run: |
+          echo ""
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [3/9]: Import & Trust GPG Keys"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          cd dist/${{ env.RELEASE_VERSION }}
+          
+          echo "Downloading KEYS file from ${KEYS_URL}..."
+          if ! wget -q "${KEYS_URL}" -O KEYS; then
+            echo "Error: Failed to download KEYS file from ${KEYS_URL}"
+            exit 1
+          fi
+          echo "✓ KEYS file downloaded"
+          
+          echo "Importing GPG keys..."
+          IMPORT_OUTPUT=$(gpg --import KEYS 2>&1)
+          IMPORTED_COUNT=$(echo "$IMPORT_OUTPUT" | grep -c "imported" || echo 
"0")
+          
+          if [[ "$IMPORTED_COUNT" == "0" ]]; then
+            echo "⚠ No new keys imported (may already exist in keyring)"
+          else
+            echo "✓ Imported GPG keys"
+          fi
+          
+          # Trust specific user key
+          if ! gpg --list-keys "${{ env.GPG_USER }}" &>/dev/null; then
+            echo "Error: User '${{ env.GPG_USER }}' key not found in imported 
keys. Please verify the username."
+            exit 1
+          fi
+          
+          echo "Trusting GPG key for user: ${{ env.GPG_USER }}"
+          echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "${{ 
env.GPG_USER }}" trust 2>/dev/null
+          echo "✓ Trusted key for ${{ env.GPG_USER }}"
+          
+          # Trust all imported keys
+          echo "Trusting all imported public keys..."
+          TRUSTED=0
+          for key in $(gpg --no-tty --list-keys --with-colons | awk -F: 
'/^pub/ {print $5}'); do
+            echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "$key" 
trust 2>/dev/null
+            TRUSTED=$((TRUSTED + 1))
+          done
+          echo "✓ Trusted $TRUSTED GPG keys"
+
+      - name: Step 4 - Verify SHA512 & GPG Signatures
+        run: |
+          echo ""
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [4/9]: Verify SHA512 & GPG Signatures"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          cd dist/${{ env.RELEASE_VERSION }}
+          
+          PACKAGE_COUNT=0
+          for pkg in *.tar.gz; do
+            if [[ -f "$pkg" ]]; then
+              PACKAGE_COUNT=$((PACKAGE_COUNT + 1))
+            fi
+          done
+          
+          CURRENT=0
+          for pkg in *.tar.gz; do
+            if [[ ! -f "$pkg" ]]; then
+              continue
+            fi
+            CURRENT=$((CURRENT + 1))
+            echo "  [${CURRENT}/${PACKAGE_COUNT}] $pkg"
+            
+            # Check SHA512
+            if shasum -a 512 --check "${pkg}.sha512"; then
+              echo "  ✓ SHA512 verified: $pkg"
+            else
+              echo "  ✗ SHA512 verification failed: $pkg"
+              exit 1
+            fi
+            
+            # Check GPG signature
+            if gpg --verify "${pkg}.asc" "$pkg" 2>&1 | grep -q "Good 
signature"; then
+              echo "  ✓ GPG signature verified: $pkg"
+            else
+              echo "  ✗ GPG signature verification failed: $pkg"
+              exit 1
+            fi
+          done
+
+      - name: Step 5 - Validate Source Packages
+        run: |
+          echo ""
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [5/9]: Validate Source Packages"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          cd dist/${{ env.RELEASE_VERSION }}
+          
+          SRC_PACKAGES=()
+          for pkg in *-src.tar.gz; do
+            if [[ -f "$pkg" ]]; then
+              SRC_PACKAGES+=("$pkg")
+            fi
+          done
+          
+          echo "Found ${#SRC_PACKAGES[@]} source package(s)"
+          
+          for src_pkg in "${SRC_PACKAGES[@]}"; do
+            echo ""
+            echo "Validating source package: $src_pkg"
+            
+            # Extract package
+            PACKAGE_DIR=$(basename "$src_pkg" .tar.gz)
+            rm -rf "$PACKAGE_DIR"
+            tar -xzf "$src_pkg"
+            
+            if [[ ! -d "$PACKAGE_DIR" ]]; then
+              echo "Error: Failed to extract package: $src_pkg"
+              exit 1
+            fi
+            
+            pushd "$PACKAGE_DIR"
+            
+            # 5.1: Check incubating name
+            if [[ ! "$src_pkg" =~ "incubating" ]]; then
+              echo "Error: Package name '$src_pkg' should include 'incubating'"
+              exit 1
+            fi
+            echo "  ✓ Package name includes 'incubating'"
+            
+            # 5.2: Check required files
+            if [[ ! -f "LICENSE" ]]; then
+              echo "Error: Package '$src_pkg' missing LICENSE file"
+              exit 1
+            fi
+            echo "  ✓ LICENSE file exists"
+            
+            if [[ ! -f "NOTICE" ]]; then
+              echo "Error: Package '$src_pkg' missing NOTICE file"
+              exit 1
+            fi
+            echo "  ✓ NOTICE file exists"
+            
+            if [[ ! -f "DISCLAIMER" ]]; then
+              echo "Error: Package '$src_pkg' missing DISCLAIMER file"
+              exit 1
+            fi
+            echo "  ✓ DISCLAIMER file exists"
+            
+            # 5.3: Check license categories (Category X - Prohibited)
+            CAT_X_MATCHES=$(grep -r -E "${{ env.CATEGORY_X }}" LICENSE NOTICE 
2>/dev/null || true)
+            CAT_X_COUNT=$(echo "$CAT_X_MATCHES" | grep -v '^$' | wc -l | tr -d 
' ')
+            
+            if [[ $CAT_X_COUNT -ne 0 ]]; then
+              echo "Error: Package '$src_pkg' contains $CAT_X_COUNT prohibited 
ASF Category X license(s):"
+              echo "$CAT_X_MATCHES"
+              exit 1
+            fi
+            echo "  ✓ No Category X licenses found"
+            
+            # 5.4: Check license categories (Category B - Warning)
+            CAT_B_COUNT=$(grep -r -E "${{ env.CATEGORY_B }}" LICENSE NOTICE 
2>/dev/null | wc -l | tr -d ' ' || echo "0")
+            if [[ $CAT_B_COUNT -ne 0 ]]; then
+              echo "  ⚠ Warning: Package '$src_pkg' contains $CAT_B_COUNT ASF 
Category B license(s) - please verify documentation"
+            else
+              echo "  ✓ No Category B licenses found"
+            fi
+            
+            # 5.5: Check empty files and directories
+            EMPTY_DIRS=$(find . -type d -empty 2>/dev/null || true)
+            EMPTY_FILES=$(find . -type f -empty 2>/dev/null || true)
+            
+            if [[ -n "$EMPTY_DIRS" ]]; then
+              echo "Error: Package '$src_pkg' contains empty director(y/ies):"
+              echo "$EMPTY_DIRS"
+              exit 1
+            fi
+            
+            if [[ -n "$EMPTY_FILES" ]]; then
+              echo "Error: Package '$src_pkg' contains empty file(s):"
+              echo "$EMPTY_FILES"
+              exit 1
+            fi
+            echo "  ✓ No empty files or directories"
+            
+            # 5.6: Check file sizes
+            LARGE_FILES=$(find . -type f -size "+${{ env.MAX_FILE_SIZE }}" 
2>/dev/null || true)
+            if [[ -n "$LARGE_FILES" ]]; then
+              echo "Error: Package '$src_pkg' contains file(s) larger than ${{ 
env.MAX_FILE_SIZE }}:"
+              echo "$LARGE_FILES"
+              exit 1
+            fi
+            echo "  ✓ All files are within size limit"
+            
+            # 5.7: Check binary files
+            BINARY_COUNT=0
+            UNDOCUMENTED_COUNT=0
+            while IFS= read -r binary_file; do
+              BINARY_COUNT=$((BINARY_COUNT + 1))
+              FILE_NAME=$(basename "$binary_file")
+              if ! grep -q "$FILE_NAME" LICENSE 2>/dev/null; then
+                echo "Error: Undocumented binary file: $binary_file"
+                UNDOCUMENTED_COUNT=$((UNDOCUMENTED_COUNT + 1))
+              fi
+            done < <(find . -type f 2>/dev/null | perl -lne 'print if -B $_' 
|| true)
+            
+            if [[ $BINARY_COUNT -eq 0 ]]; then
+              echo "  ✓ No binary files found"
+            elif [[ $UNDOCUMENTED_COUNT -eq 0 ]]; then
+              echo "  ✓ All $BINARY_COUNT binary file(s) are documented"
+            else
+              echo "Error: Found $UNDOCUMENTED_COUNT undocumented binary 
file(s)"
+              exit 1
+            fi
+            
+            # 5.8: Check license headers in source files
+            echo "  Checking for ASF license headers in source files..."
+            
+            # Define file patterns to check
+            FILE_PATTERNS=("*.java" "*.sh" "*.py" "*.go" "*.js" "*.ts" "*.jsx" 
"*.tsx" "*.c" "*.h" "*.cpp" "*.cc" "*.cxx" "*.hpp" "*.scala" "*.groovy" 
"*.gradle" "*.rs" "*.kt" "*.proto")
+            
+            # Files to exclude
+            EXCLUDE_PATTERNS=("*.min.js" "*.min.css" "*node_modules*" 
"*target*" "*build*" "*.pb.go" "*generated*" "*third_party*" "*vendor*")
+            
+            FILES_WITHOUT_LICENSE=()
+            TOTAL_CHECKED=0
+            EXCLUDED_COUNT=0
+            DOCUMENTED_COUNT=0
+            
+            # Build find command
+            FIND_CMD="find . -type f \\("
+            FIRST=1
+            for pattern in "${FILE_PATTERNS[@]}"; do
+              if [[ $FIRST -eq 1 ]]; then
+                FIND_CMD="$FIND_CMD -name \"$pattern\""
+                FIRST=0
+              else
+                FIND_CMD="$FIND_CMD -o -name \"$pattern\""
+              fi
+            done
+            FIND_CMD="$FIND_CMD \\) 2>/dev/null"
+            
+            # Check each source file
+            while IFS= read -r source_file; do
+              # Skip if file matches exclude patterns
+              SHOULD_EXCLUDE=0
+              for exclude_pattern in "${EXCLUDE_PATTERNS[@]}"; do
+                if [[ "$source_file" == $exclude_pattern ]]; then
+                  SHOULD_EXCLUDE=1
+                  EXCLUDED_COUNT=$((EXCLUDED_COUNT + 1))
+                  break
+                fi
+              done
+              
+              if [[ $SHOULD_EXCLUDE -eq 1 ]]; then
+                continue
+              fi
+              
+              TOTAL_CHECKED=$((TOTAL_CHECKED + 1))
+              
+              # Check first 30 lines for Apache license header
+              if ! head -n 30 "$source_file" | grep -q "Licensed to the Apache 
Software Foundation"; then
+                # Check if documented in LICENSE file
+                FILE_NAME=$(basename "$source_file")
+                FILE_PATH_RELATIVE=$(echo "$source_file" | sed 's|^\./||')
+                
+                if [[ -f "LICENSE" ]] && (grep -q "$FILE_NAME" LICENSE 
2>/dev/null || grep -q "$FILE_PATH_RELATIVE" LICENSE 2>/dev/null); then

Review Comment:
   ⚠️ important — The exemption uses `grep -q "$FILE_NAME" LICENSE`, which is 
an unanchored regex over the basename. A LICENSE entry for another path with 
the same basename can exempt an unrelated file, and regex metacharacters in the 
basename change the match. Require an exact normalized relative-path match with 
fixed-string semantics and remove the basename fallback.



##########
.github/workflows/validate-release-new.yml:
##########
@@ -0,0 +1,805 @@
+name: "Validate Apache Release (New)"
+
+on:
+  workflow_dispatch:
+    inputs:
+      release_version:
+        required: true
+        description: svn release version
+        default: '1.7.0'
+      gpg_user:
+        required: true
+        description: current release manager (gpg username)
+        default: 'pengjunzhi'
+      java_version:
+        required: false
+        description: Java version to validate
+        default: '11'
+        type: choice
+        options:
+          - '11'
+          - '17'
+
+  push:
+    branches:
+      - 'release-*'
+  pull_request:
+    branches:
+      - 'release-*'
+
+jobs:
+  validate:
+    name: "Validate Release On ${{ matrix.os }} (java-${{ matrix.java_version 
}})"
+    runs-on: ${{ matrix.os }}
+    env:
+      RELEASE_VERSION: ${{ inputs.release_version || '1.7.0' }}
+      GPG_USER: ${{ inputs.gpg_user || 'pengjunzhi' }}
+      JAVA_VERSION: ${{ inputs.java_version || matrix.java_version || '11' }}
+      SVN_URL_PREFIX: 
https://dist.apache.org/repos/dist/dev/incubator/hugegraph
+      KEYS_URL: https://downloads.apache.org/incubator/hugegraph/KEYS
+      MAX_FILE_SIZE: 800k
+      SERVER_START_DELAY: 3
+      # License Patterns (ASF Category X - Prohibited)
+      CATEGORY_X: '\bGPL|\bLGPL|Sleepycat 
License|BSD-4-Clause|\bBCL\b|JSR-275|Amazon Software 
License|\bRSAL\b|\bQPL\b|\bSSPL|\bCPOL|\bNPL1|Creative Commons 
Non-Commercial|JSON\.org'
+      # License Patterns (ASF Category B - Must be documented)
+      CATEGORY_B: '\bCDDL1|\bCPL|\bEPL|\bIPL|\bMPL|\bSPL|OSL-3.0|UnRAR 
License|Erlang Public License|\bOFL\b|Ubuntu Font License Version 1.0|IPA Font 
License Agreement v1.0|EPL2.0|CC-BY'
+    steps:
+      - name: Checkout source
+        uses: actions/checkout@v4
+
+      - name: Install JDK ${{ env.JAVA_VERSION }}
+        uses: actions/setup-java@v3
+        with:
+          java-version: ${{ env.JAVA_VERSION }}
+          distribution: 'adopt'
+
+      - name: Install dependencies
+        run: |
+          if [[ "${{ runner.os }}" == "macOS" ]]; then
+            brew install svn wget perl
+          elif [[ "${{ runner.os }}" == "Linux" ]]; then
+            sudo apt-get update
+            sudo apt-get install -y subversion wget perl
+          fi
+          # Verify all required commands
+          for cmd in svn gpg shasum mvn java wget tar curl awk grep find perl; 
do
+            if ! command -v "$cmd" &> /dev/null; then
+              echo "Error: Missing required dependency: $cmd"
+              exit 1
+            fi
+            echo "✓ $cmd: $(command -v $cmd)"
+          done
+
+      - name: Cache Maven packages
+        uses: actions/cache@v3
+        with:
+          path: ~/.m2
+          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+          restore-keys: ${{ runner.os }}-m2
+
+      - name: Step 1 - Check Dependencies
+        run: |
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [1/9]: Check Dependencies"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          # Check Java version
+          CURRENT_JAVA=$(java -version 2>&1 | head -n 1 | awk -F '"' '{print 
$2}' | awk -F '.' '{print $1}')
+          echo "Current Java version: $CURRENT_JAVA (Required: ${{ 
env.JAVA_VERSION }})"
+          if [[ "$CURRENT_JAVA" != "${{ env.JAVA_VERSION }}" ]]; then
+            echo "Error: Java version mismatch! Current: Java $CURRENT_JAVA, 
Required: Java ${{ env.JAVA_VERSION }}"
+            exit 1
+          fi
+          echo "✓ Java version check passed: Java $CURRENT_JAVA"
+
+      - name: Step 2 - Prepare Release Files
+        run: |
+          echo ""
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [2/9]: Prepare Release Files"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          DIST_DIR="dist/${{ env.RELEASE_VERSION }}"
+          echo "Downloading from SVN to: ${DIST_DIR}"
+          
+          rm -rf "${DIST_DIR}"
+          mkdir -p "${DIST_DIR}"
+          
+          if ! svn co "${SVN_URL_PREFIX}/${{ env.RELEASE_VERSION }}" 
"${DIST_DIR}"; then
+            echo "Error: Failed to download from SVN: ${SVN_URL_PREFIX}/${{ 
env.RELEASE_VERSION }}"
+            exit 1
+          fi
+          
+          echo "✓ Downloaded release files from SVN"
+          cd "${DIST_DIR}"
+          ls -lh
+
+      - name: Step 3 - Import & Trust GPG Keys
+        run: |
+          echo ""
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [3/9]: Import & Trust GPG Keys"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          cd dist/${{ env.RELEASE_VERSION }}
+          
+          echo "Downloading KEYS file from ${KEYS_URL}..."
+          if ! wget -q "${KEYS_URL}" -O KEYS; then
+            echo "Error: Failed to download KEYS file from ${KEYS_URL}"
+            exit 1
+          fi
+          echo "✓ KEYS file downloaded"
+          
+          echo "Importing GPG keys..."
+          IMPORT_OUTPUT=$(gpg --import KEYS 2>&1)
+          IMPORTED_COUNT=$(echo "$IMPORT_OUTPUT" | grep -c "imported" || echo 
"0")
+          
+          if [[ "$IMPORTED_COUNT" == "0" ]]; then
+            echo "⚠ No new keys imported (may already exist in keyring)"
+          else
+            echo "✓ Imported GPG keys"
+          fi
+          
+          # Trust specific user key
+          if ! gpg --list-keys "${{ env.GPG_USER }}" &>/dev/null; then
+            echo "Error: User '${{ env.GPG_USER }}' key not found in imported 
keys. Please verify the username."
+            exit 1
+          fi
+          
+          echo "Trusting GPG key for user: ${{ env.GPG_USER }}"
+          echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "${{ 
env.GPG_USER }}" trust 2>/dev/null
+          echo "✓ Trusted key for ${{ env.GPG_USER }}"
+          
+          # Trust all imported keys
+          echo "Trusting all imported public keys..."
+          TRUSTED=0
+          for key in $(gpg --no-tty --list-keys --with-colons | awk -F: 
'/^pub/ {print $5}'); do
+            echo -e "5\ny\n" | gpg --batch --command-fd 0 --edit-key "$key" 
trust 2>/dev/null
+            TRUSTED=$((TRUSTED + 1))
+          done
+          echo "✓ Trusted $TRUSTED GPG keys"
+
+      - name: Step 4 - Verify SHA512 & GPG Signatures
+        run: |
+          echo ""
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [4/9]: Verify SHA512 & GPG Signatures"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          cd dist/${{ env.RELEASE_VERSION }}
+          
+          PACKAGE_COUNT=0
+          for pkg in *.tar.gz; do
+            if [[ -f "$pkg" ]]; then
+              PACKAGE_COUNT=$((PACKAGE_COUNT + 1))
+            fi
+          done
+          
+          CURRENT=0
+          for pkg in *.tar.gz; do
+            if [[ ! -f "$pkg" ]]; then
+              continue
+            fi
+            CURRENT=$((CURRENT + 1))
+            echo "  [${CURRENT}/${PACKAGE_COUNT}] $pkg"
+            
+            # Check SHA512
+            if shasum -a 512 --check "${pkg}.sha512"; then
+              echo "  ✓ SHA512 verified: $pkg"
+            else
+              echo "  ✗ SHA512 verification failed: $pkg"
+              exit 1
+            fi
+            
+            # Check GPG signature
+            if gpg --verify "${pkg}.asc" "$pkg" 2>&1 | grep -q "Good 
signature"; then
+              echo "  ✓ GPG signature verified: $pkg"
+            else
+              echo "  ✗ GPG signature verification failed: $pkg"
+              exit 1
+            fi
+          done
+
+      - name: Step 5 - Validate Source Packages
+        run: |
+          echo ""
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          echo "Step [5/9]: Validate Source Packages"
+          echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+          
+          cd dist/${{ env.RELEASE_VERSION }}
+          
+          SRC_PACKAGES=()
+          for pkg in *-src.tar.gz; do
+            if [[ -f "$pkg" ]]; then
+              SRC_PACKAGES+=("$pkg")
+            fi
+          done
+          
+          echo "Found ${#SRC_PACKAGES[@]} source package(s)"
+          
+          for src_pkg in "${SRC_PACKAGES[@]}"; do
+            echo ""
+            echo "Validating source package: $src_pkg"
+            
+            # Extract package
+            PACKAGE_DIR=$(basename "$src_pkg" .tar.gz)
+            rm -rf "$PACKAGE_DIR"
+            tar -xzf "$src_pkg"
+            
+            if [[ ! -d "$PACKAGE_DIR" ]]; then
+              echo "Error: Failed to extract package: $src_pkg"
+              exit 1
+            fi
+            
+            pushd "$PACKAGE_DIR"
+            
+            # 5.1: Check incubating name
+            if [[ ! "$src_pkg" =~ "incubating" ]]; then
+              echo "Error: Package name '$src_pkg' should include 'incubating'"
+              exit 1
+            fi
+            echo "  ✓ Package name includes 'incubating'"
+            
+            # 5.2: Check required files
+            if [[ ! -f "LICENSE" ]]; then
+              echo "Error: Package '$src_pkg' missing LICENSE file"
+              exit 1
+            fi
+            echo "  ✓ LICENSE file exists"
+            
+            if [[ ! -f "NOTICE" ]]; then
+              echo "Error: Package '$src_pkg' missing NOTICE file"
+              exit 1
+            fi
+            echo "  ✓ NOTICE file exists"
+            
+            if [[ ! -f "DISCLAIMER" ]]; then
+              echo "Error: Package '$src_pkg' missing DISCLAIMER file"
+              exit 1
+            fi
+            echo "  ✓ DISCLAIMER file exists"
+            
+            # 5.3: Check license categories (Category X - Prohibited)
+            CAT_X_MATCHES=$(grep -r -E "${{ env.CATEGORY_X }}" LICENSE NOTICE 
2>/dev/null || true)
+            CAT_X_COUNT=$(echo "$CAT_X_MATCHES" | grep -v '^$' | wc -l | tr -d 
' ')
+            
+            if [[ $CAT_X_COUNT -ne 0 ]]; then
+              echo "Error: Package '$src_pkg' contains $CAT_X_COUNT prohibited 
ASF Category X license(s):"
+              echo "$CAT_X_MATCHES"
+              exit 1
+            fi
+            echo "  ✓ No Category X licenses found"
+            
+            # 5.4: Check license categories (Category B - Warning)
+            CAT_B_COUNT=$(grep -r -E "${{ env.CATEGORY_B }}" LICENSE NOTICE 
2>/dev/null | wc -l | tr -d ' ' || echo "0")
+            if [[ $CAT_B_COUNT -ne 0 ]]; then
+              echo "  ⚠ Warning: Package '$src_pkg' contains $CAT_B_COUNT ASF 
Category B license(s) - please verify documentation"
+            else
+              echo "  ✓ No Category B licenses found"
+            fi
+            
+            # 5.5: Check empty files and directories
+            EMPTY_DIRS=$(find . -type d -empty 2>/dev/null || true)
+            EMPTY_FILES=$(find . -type f -empty 2>/dev/null || true)
+            
+            if [[ -n "$EMPTY_DIRS" ]]; then
+              echo "Error: Package '$src_pkg' contains empty director(y/ies):"
+              echo "$EMPTY_DIRS"
+              exit 1
+            fi
+            
+            if [[ -n "$EMPTY_FILES" ]]; then
+              echo "Error: Package '$src_pkg' contains empty file(s):"
+              echo "$EMPTY_FILES"
+              exit 1
+            fi
+            echo "  ✓ No empty files or directories"
+            
+            # 5.6: Check file sizes
+            LARGE_FILES=$(find . -type f -size "+${{ env.MAX_FILE_SIZE }}" 
2>/dev/null || true)
+            if [[ -n "$LARGE_FILES" ]]; then
+              echo "Error: Package '$src_pkg' contains file(s) larger than ${{ 
env.MAX_FILE_SIZE }}:"
+              echo "$LARGE_FILES"
+              exit 1
+            fi
+            echo "  ✓ All files are within size limit"
+            
+            # 5.7: Check binary files
+            BINARY_COUNT=0
+            UNDOCUMENTED_COUNT=0
+            while IFS= read -r binary_file; do
+              BINARY_COUNT=$((BINARY_COUNT + 1))
+              FILE_NAME=$(basename "$binary_file")
+              if ! grep -q "$FILE_NAME" LICENSE 2>/dev/null; then
+                echo "Error: Undocumented binary file: $binary_file"
+                UNDOCUMENTED_COUNT=$((UNDOCUMENTED_COUNT + 1))
+              fi
+            done < <(find . -type f 2>/dev/null | perl -lne 'print if -B $_' 
|| true)
+            
+            if [[ $BINARY_COUNT -eq 0 ]]; then
+              echo "  ✓ No binary files found"
+            elif [[ $UNDOCUMENTED_COUNT -eq 0 ]]; then
+              echo "  ✓ All $BINARY_COUNT binary file(s) are documented"
+            else
+              echo "Error: Found $UNDOCUMENTED_COUNT undocumented binary 
file(s)"
+              exit 1
+            fi
+            
+            # 5.8: Check license headers in source files
+            echo "  Checking for ASF license headers in source files..."
+            
+            # Define file patterns to check
+            FILE_PATTERNS=("*.java" "*.sh" "*.py" "*.go" "*.js" "*.ts" "*.jsx" 
"*.tsx" "*.c" "*.h" "*.cpp" "*.cc" "*.cxx" "*.hpp" "*.scala" "*.groovy" 
"*.gradle" "*.rs" "*.kt" "*.proto")

Review Comment:
   ⚠️ important — The source-package header scan only visits the listed 
extensions and omits header-bearing files such as `pom.xml`, 
XML/YAML/properties, HTML, and CSS. Those files can lack an Apache header while 
the workflow reports that all checked files passed. Replace this partial 
allowlist with Apache RAT or an equivalent comprehensive scan, keeping only 
narrowly justified exclusions.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to