ci(secu): check dependency actions #118
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: dependency-checks | |
| on: | |
| pull_request: | |
| workflow_call: | |
| inputs: | |
| module_directory: | |
| description: 'Component path' | |
| required: false | |
| default: "" | |
| type: string | |
| permissions: | |
| contents: read | |
| env: | |
| minimum_package_age_hours: 1 # 168 # 7 days | |
| jobs: | |
| dependency-scan: | |
| name: Run safe-chain analysis | |
| runs-on: ${{ github.repository_visibility != 'public' && 'centreon-security' || 'ubuntu-24.04' }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Pnpm | |
| uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 | |
| with: | |
| version: 10 | |
| - name: Setup Node | |
| uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 | |
| with: | |
| node-version: 22 | |
| package-manager-cache: true | |
| - name: Install safe-chain | |
| run: | | |
| max_retries=5 | |
| retry_delay=5 | |
| for ((i=1; i<=max_retries; i++)); do | |
| if curl -fsSL https://github.com/AikidoSec/safe-chain/releases/latest/download/install-safe-chain.sh | sh -s -- --ci; then | |
| echo "Success on attempt $i" | |
| exit 0 | |
| else | |
| echo "Attempt $i failed. Retrying in $retry_delay seconds..." | |
| sleep $retry_delay | |
| fi | |
| done | |
| echo "All $max_retries attempts failed." | |
| exit 1 | |
| shell: bash | |
| - name: Check dependencies and managers | |
| run: | | |
| set +x | |
| # Check override | |
| if [ "${{ vars.OVERRIDE_ALL_DEPENDENCY_SCAN }}" == "true" ]; then | |
| echo "[DEBUG] - Global scan override enabled" | |
| return 0 | |
| elif [[ "${{ vars.OVERRIDE_PNPM_COMPLIANCE }}" == "true" ]]; then | |
| echo "[DEBUG] - PNPM scan override enabled" | |
| return 0 | |
| fi | |
| # Check date | |
| current_timestamp=$(date +%s) | |
| DUE_DATE="${{ vars.OVERRIDE_DEPENDENCY_ENFORCEMENT_DATE }}" | |
| input_timestamp=$(date -d "$DUE_DATE" +%s) | |
| # Setup vars | |
| export SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS=${{ env.minimum_package_age_hours }} | |
| export SAFE_CHAIN_LOGGING="silent" | |
| ERROR_LOG="error_log.txt" | |
| FORCE_FAIL="false" | |
| ENFORCEMENT="false" | |
| if [ "$current_timestamp" -ge "$input_timestamp" ]; then | |
| echo "[DEBUG]: Deadline passed." | |
| ENFORCEMENT="true" | |
| fi | |
| function message_type() { | |
| if [ $ENFORCEMENT == "true" ]; then | |
| echo "[ERROR] : $1" >> "$ERROR_LOG" | |
| FORCE_FAIL="true" | |
| else | |
| echo "[WARNING] : $1" >> "$ERROR_LOG" | |
| fi | |
| } | |
| # Compare pnpm version used in lockfile | |
| function compare_version() { | |
| MIN_VERSION="10.0.0" | |
| LOC_VERSION=$(grep -E '^lockfileVersion:' "$LOC_TYPE" \ | |
| | awk '{print $2}' \ | |
| | tr -d "'\"") | |
| # Compare versions | |
| version_ge() { | |
| [ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" = "$2" ] | |
| } | |
| if version_ge "$MIN_VERSION" "$LOC_VERSION"; then | |
| message_type "lockfileVersion $LOC_VERSION < $MIN_VERSION in $LOC_FILE" | |
| echo "[DEBUG] - LOC-VERSION = $LOC_VERSION" | |
| echo "[DEBUG] - corepack version" | |
| corepack -v | |
| #echo "[DEBUG] - downgrade PNPM version" | |
| if version_ge "$LOC_VERSION" "7.1.3"; then | |
| message_type "lockfileVersion $LOC_VERSION < $MIN_VERSION in $LOC_FILE" | |
| echo "[DEBUG] - MAX_VERSION = 7.1.3" | |
| echo "[DEBUG] - add PNPM specific conf" | |
| corepack prepare npm@$"LOC_VERSION" --activate /dev/null 2>&1 | |
| pnpm config list | |
| pnpm config set auto-install-peers false | |
| else | |
| echo "[DEBUG] - MAX_vERSION is upper 7.1.3" | |
| corepack use pnpm@"$LOC_VERSION" /dev/null 2>&1 | |
| fi | |
| fi | |
| } | |
| # Move to module folder and find manifests | |
| MODULE_FOLDER="${{ inputs.module_directory }}" || "" | |
| if [[ -n "$MODULE_FOLDER" ]]; then | |
| cd $MODULE_FOLDER | |
| fi | |
| touch "$ERROR_LOG" | |
| echo "[INFO] - Find manifest files" | |
| DEP_FILES=($(find ./ -type f -name "package.json")) | |
| # Scan node manifests | |
| for DEP_FILE in ${DEP_FILES[@]}; do | |
| DEP_DIR=$(dirname $DEP_FILE) | |
| echo "[INFO] - Scanning $DEP_FILE" | |
| echo "[DEBUG] - DEP_FILE = $DEP_FILE" | |
| LOC_FILES=($(find $DEP_DIR -type f -name "package-lock.json" -o -name "pnpm-lock.yaml" -o -name "yarn.lock")) | |
| COUNT=0 | |
| for LOC_FILE in ${LOC_FILES[@]}; do | |
| LOC_TYPE=$(basename $LOC_FILE) | |
| LOC_DIR=$(dirname $LOC_FILE) | |
| cd $LOC_DIR | |
| case $LOC_TYPE in | |
| "yarn.lock") | |
| COUNT=$((COUNT+1)) | |
| message_type "Yarn is no longer allowed. Kindly replace the lockfile using PNPM : $LOC_FILE" | |
| ;; | |
| "package-lock.json") | |
| COUNT=$((COUNT+1)) | |
| message_type "NPM is no longer allowed. Kindly replace the lockfile using PNPM : $LOC_FILE" | |
| ;; | |
| "pnpm-lock.yaml") | |
| echo "[DEBUG] - pnpm version before compare" | |
| pnpm --version | |
| echo "[DEBUG] - pnpm conf before compare" | |
| pnpm config list | |
| echo "[DEBUG] - compare version start" | |
| compare_version | |
| #corepack use pnpm@"$LOC_VERSION" | |
| #corepack install --global pnpm@"$LOC_VERSION" | |
| echo "[DEBUG] - pnpm version after compare" | |
| pnpm --version | |
| echo "[DEBUG] - pnpm conf after compare" | |
| pnpm config list | |
| pnpm config list | |
| echo "[DEBUG] - check manifests" | |
| ls -la package.json | |
| ls -la pnpm-lock.yaml | |
| cat package.json | |
| echo "[DEBUG] - LOC_FILE = $LOC_FILE" | |
| echo "[DEBUG] - LOC_DIR = $LOC_DIR" | |
| echo "[DEBUG] - safe chain start" | |
| echo "[DEBUG] - get pnpm version | |
| node -v | |
| echo "[DEBUG] - get node version | |
| pnpm -v | |
| pnpm install --frozen-lockfile --loglevel warn --safe-chain-logging=verbose | |
| #pnpm install --frozen-lockfile --safe-chain-logging=verbose | |
| COUNT=$((COUNT+1)) | |
| ;; | |
| "*") | |
| message_type "no lockfile found in $LOC_DIR" | |
| ;; | |
| esac | |
| cd - | |
| done | |
| if [[ $COUNT -gt 1 ]]; then | |
| message_type "$COUNT lockfiles were found. Kindly keep only the lockfile generated with PNPM : $LOC_DIR" | |
| fi | |
| echo "[DEBUG] - COUNT = $COUNT" | |
| done | |
| echo "[DEBUG] - FORCE_FAIL = $FORCE_FAIL" | |
| if [ -s "$ERROR_LOG" ]; then | |
| cat "$ERROR_LOG" | |
| if [ "FORCE_FAIL" == "true" ]; then | |
| echo "[FATAL]: Breaking the run." | |
| exit 1 | |
| fi | |
| else | |
| echo "[INFO] - OK nothing found" | |
| fi | |
| shell: bash | |
| dependency-blacklist: | |
| name: Run blacklist analysis | |
| runs-on: ${{ github.repository_visibility != 'public' && 'centreon-security' || 'ubuntu-24.04' }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for blacklisted dependencies | |
| run: | | |
| # Check override | |
| if [ "${{ vars.OVERRIDE_DEPENDENCY_SCAN }}" == "true" ]; then | |
| echo "[DEBUG] - Global scan override enabled" | |
| return 0 | |
| elif [[ "${{ vars.OVERRIDE_BLACKLIST_COMPLIANCE }}" == "true" ]]; then | |
| echo "[DEBUG] - Blacklist scan override enabled" | |
| return 0 | |
| fi | |
| function checkPnpmLockfile() { | |
| # Find dependency formated as | |
| # "name@version:" | |
| if grep -qF "$NAME@$VERSION" "$LOCKFILE"; then | |
| echo "$NAME:$VERSION was found in $LOCKFILE" | |
| echo "[ERROR] - $NAME:$VERSION was found in $LOCKFILE" >> "$ERROR_LOG" | |
| else | |
| echo -n "." | |
| fi | |
| } | |
| function checkManifest() { | |
| COUNT=0 | |
| echo "[INFO] - Testing manifest $LOCKFILE" | |
| manifest_type=$(basename "$LOCKFILE") | |
| while IFS=':' read -r NAME VERSION; do | |
| # ignore empty and commented lines | |
| [[ -z "${NAME// }" ]] && continue | |
| [[ "$NAME" =~ ^# ]] && continue | |
| case "$manifest_type" in | |
| "pnpm-lock.yaml") | |
| checkPnpmLockfile | |
| ;; | |
| "yarn.lock") | |
| echo "[ERROR] - dependency manager not allowed. Found in $LOCKFILE" >> "$ERROR_LOG" | |
| ;; | |
| "package-lock.json") | |
| echo "[ERROR] - dependency manager not allowed. Found in $LOCKFILE" >> "$ERROR_LOG" | |
| ;; | |
| "*") | |
| echo "[ERROR] - dependency manager not managed. Found in $LOCKFILE" >> "$ERROR_LOG" | |
| esac | |
| COUNT=$((COUNT+1)) | |
| done < "$DEP_LIST" | |
| echo "[INFO] - Scanned $COUNT IOC" | |
| } | |
| DEP_LIST="compromised-packages.txt" | |
| if [ -f "$DEP_LIST" ]; then rm -f "$DEP_LIST"; fi | |
| wget https://raw.githubusercontent.com/centreon/security-tools/main/blacklist/"$DEP_LIST" | |
| ERROR_LOG="error_log.txt" | |
| touch "$ERROR_LOG" | |
| LOCKFILES=($(find ./ -type f -name "pnpm-lock.yaml")) | |
| for LOCKFILE in "${LOCKFILES[@]}"; do | |
| checkManifest "$LOCKFILE" | |
| done | |
| if [ -s "$ERROR_LOG" ]; then | |
| echo -e "[ERROR]: Breaking the run as following ERRORS were found:" | |
| cat "$ERROR_LOG" | |
| exit 1 | |
| else | |
| echo "[INFO] - OK nothing found" | |
| fi | |
| shell: bash |