From 7b449b652d946a8eef9aca65f0c8e182b4fb80f7 Mon Sep 17 00:00:00 2001 From: lorecraft-io Date: Sat, 4 Apr 2026 20:45:51 -0400 Subject: [PATCH 1/4] Fix grep exit-code-2 bug + add README-SECTIONS updates for /safetycheck - Replace all explicit missing-file grep args with --include= style to prevent exit code 2 false negatives across Checks 14, 18, 19, 20 - Add /safetycheck row to cheat-sheet.md skills table - Add Step 9 row to step-ordering.md (was missing entirely) Co-Authored-By: claude-flow --- README-SECTIONS/cheat-sheet.md | 5 +++-- README-SECTIONS/step-ordering.md | 3 ++- step-9/safetycheck-skill/SKILL.md | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/README-SECTIONS/cheat-sheet.md b/README-SECTIONS/cheat-sheet.md index a5781a2..6e3bd97 100644 --- a/README-SECTIONS/cheat-sheet.md +++ b/README-SECTIONS/cheat-sheet.md @@ -96,9 +96,10 @@ These are custom skills installed by the setup scripts. Type them inside a Claud | `/rmini do the thing` | Step 3 | Launch a compact 5-agent swarm — same power, tighter team | | `/rhive ` | Step 3 | Launch a queen-led autonomous hive-mind with raft consensus | | `/w4w` | Step 3 | Maximum attention to detail — word for word, line for line. No skipping, no summarizing. Also works without the slash — just type `w4w` | +| `/safetycheck` | Step 9 | Security audit — scans any project for exposed keys, missing rate limiting, input sanitization gaps, dependency vulnerabilities, and insecure configurations. Also responds to "run a safety check" in plain English | -> These are **explicit triggers** — you type the command to activate the skill. This is different from the auto-triggered tools below, which respond to natural language. Exception: `/w4w` also works without the slash — just type `w4w` anywhere in your message. `/rmini` is the compact version of `/rswarm` — 5 agents instead of 15. +> These are **explicit triggers** — you type the command to activate the skill. This is different from the auto-triggered tools below, which respond to natural language. Exception: `/w4w` also works without the slash — just type `w4w` anywhere in your message. `/rmini` is the compact version of `/rswarm` — 5 agents instead of 15. `/safetycheck` also works in natural language. --- @@ -125,7 +126,7 @@ These activate on their own when Claude detects a relevant task via natural lang | Excalidraw | Add-on | Natural language — diagrams, flowcharts, whiteboard sketches | "Draw a system architecture diagram" | | Gamma | Add-on | Natural language — presentations, documents, webpages | "Create a pitch deck for my startup" | -> **Key distinction:** Slash commands (`/rswarm`, `/rmini`, `/rhive`, `/w4w`) require you to type the command. Everything in this table works by just talking to Claude naturally. +> **Key distinction:** Slash commands (`/rswarm`, `/rmini`, `/rhive`, `/w4w`, `/safetycheck`) require you to type the command. Everything in this table works by just talking to Claude naturally. > > **Add-on tools** are not part of the step-by-step setup — they're optional MCP servers you can connect separately. Claude auto-detects them when they're installed. diff --git a/README-SECTIONS/step-ordering.md b/README-SECTIONS/step-ordering.md index ec83d68..68ea7f1 100644 --- a/README-SECTIONS/step-ordering.md +++ b/README-SECTIONS/step-ordering.md @@ -14,6 +14,7 @@ Run the steps in this order: | 6 | Productivity Tools | Motion Calendar + Notion (pick what you use) | | 7 | Second Brain | Obsidian vault setup + data import (7a-7d) | | 8 | Telegram | Telegram bot setup — message Claude from your phone | +| 9 | Safety Check | Security auditing — 8 API checks + 12 MCP checks for tool poisoning, DNS rebinding, supply chain attacks | | **Final** | **Status Line** | **Final config — status indicators, system health check** | -> **Note:** Step 6 (Productivity Tools) is all optional — install only the tools you use. Step 7 (Second Brain) is the biggest step with four sub-parts (7a-7d). Step 8 (Telegram) is interactive — it walks you through creating a bot and pasting your token. The Final Step (Status Line) is the wrap-up that wires everything together — your status indicators show what's active across all the tools. +> **Note:** Step 6 (Productivity Tools) is all optional — install only the tools you use. Step 7 (Second Brain) is the biggest step with four sub-parts (7a-7d). Step 8 (Telegram) is interactive — it walks you through creating a bot and pasting your token. Step 9 (Safety Check) installs the `/safetycheck` security audit skill — 8 core checks for any project, plus 12 MCP-specific checks when an MCP project is detected (20 total). The Final Step (Status Line) is the wrap-up that wires everything together — your status indicators show what's active across all the tools. diff --git a/step-9/safetycheck-skill/SKILL.md b/step-9/safetycheck-skill/SKILL.md index eafc60d..8f93987 100644 --- a/step-9/safetycheck-skill/SKILL.md +++ b/step-9/safetycheck-skill/SKILL.md @@ -67,7 +67,7 @@ git ls-files 2>/dev/null | grep -iE "\.env$" **MCP Config scan** (if MCP detected) — Scan `.mcp.json`, `claude_desktop_config.json`, `.cursor/mcp.json` for hardcoded secrets in `env` blocks: ```bash -grep -r '"env"' .mcp.json claude_desktop_config.json .cursor/mcp.json 2>/dev/null | grep -iE '(sk-[a-zA-Z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[a-zA-Z0-9]{36}|AIzaSy[a-zA-Z0-9_-]{30,}|xox[bpsa]-[a-zA-Z0-9-]+)' +grep -rn '"env"' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null | grep -iE '(sk-[a-zA-Z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[a-zA-Z0-9]{36}|AIzaSy[a-zA-Z0-9_-]{30,}|xox[bpsa]-[a-zA-Z0-9-]+)' ``` Check if MCP configs are tracked in git: @@ -344,7 +344,7 @@ Verify TLS is enforced and DNS rebinding protection is active. **Checks:** ```bash # Check for HTTP (non-HTTPS, non-localhost) in MCP configs -grep -rniE '"url"\s*:\s*"http://' .mcp.json claude_desktop_config.json 2>/dev/null | grep -vE '(localhost|127\.0\.0\.1|::1)' +grep -rniE '"url"\s*:\s*"http://' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null | grep -vE '(localhost|127\.0\.0\.1|::1)' # Check for 0.0.0.0 binding without auth grep -rniE '(0\.0\.0\.0|host:\s*["'"'"']0\.0\.0\.0)' --include="*.ts" --include="*.js" --include="*.py" . @@ -395,10 +395,10 @@ Check for over-privileged tokens, missing expiration, and insecure storage. ```bash # Check for wildcard/broad OAuth scopes in MCP config or auth code -grep -rniE '(mail\.google\.com/|calendar\.google\.com/|drive\.google\.com/|scope.*\*|scope.*"all"|scope.*"full")' --include="*.ts" --include="*.js" --include="*.py" .mcp.json 2>/dev/null +grep -rniE '(mail\.google\.com/|calendar\.google\.com/|drive\.google\.com/|scope.*\*|scope.*"all"|scope.*"full")' --include="*.ts" --include="*.js" --include="*.py" --include=".mcp.json" . 2>/dev/null # Check for access tokens stored in plaintext -grep -rniE '("access_token"\s*:\s*"[^"]{20,}"|token\s*=\s*["'"'"'][^"'"'"']{20,})' .mcp.json claude_desktop_config.json 2>/dev/null +grep -rniE '("access_token"\s*:\s*"[^"]{20,}"|token\s*=\s*["'"'"'][^"'"'"']{20,})' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null # Check for long-lived tokens (no expiry) grep -rniE '(expires_in.*86400|expires_in.*[0-9]{6,}|no.*expir|never.*expir)' --include="*.ts" --include="*.js" . @@ -486,10 +486,10 @@ grep -rn "hostHeaderValidation\|localhostHostValidation\|createMcpExpressApp" -- ```bash # @latest floating versions in MCP config (rug-pull risk) -grep -rniE '"@latest"|npx.*@latest' .mcp.json claude_desktop_config.json .cursor/mcp.json 2>/dev/null +grep -rniE '"@latest"|npx.*@latest' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null # npx -y without pinned version (auto-install from potentially poisoned package) -grep -rniE 'npx.*-y' .mcp.json claude_desktop_config.json 2>/dev/null | grep -vE '@[0-9]' +grep -rniE 'npx.*-y' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null | grep -vE '@[0-9]' # Lockfile check ls package-lock.json yarn.lock pnpm-lock.yaml bun.lockb 2>/dev/null || echo "NO_LOCKFILE" @@ -498,7 +498,7 @@ ls package-lock.json yarn.lock pnpm-lock.yaml bun.lockb 2>/dev/null || echo "NO_ node -e "const p=require('./package.json'); console.log(p.files ? 'HAS_FILES_WHITELIST' : 'NO_FILES_WHITELIST');" 2>/dev/null # Shell metacharacters in MCP config args (command injection via config) -grep -rniE '"args"\s*:\s*\[' .mcp.json claude_desktop_config.json 2>/dev/null | grep -E '[;|&\$\`]' +grep -rniE '"args"\s*:\s*\[' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null | grep -E '[;|&\$\`]' ``` **Severity**: HIGH for `@latest` in MCP config. HIGH for no lockfile. HIGH for shell metacharacters in args arrays. MEDIUM for no files whitelist on published MCP server. PASS if pinned and locked. @@ -515,13 +515,13 @@ Verify tool invocations are logged with structured data. ```bash # Check for structured logging library -grep -rn "winston\|pino\|bunyan\|log4js\|structlog\|logging\.getLogger" package.json requirements.txt 2>/dev/null +grep -rn "winston\|pino\|bunyan\|log4js\|structlog\|logging\.getLogger" . --include="package.json" --include="requirements.txt" 2>/dev/null # Check for MCP logging notifications grep -rn "sendLoggingMessage\|LoggingMessageNotification\|setLoggingLevel\|notifications/message" --include="*.ts" --include="*.js" . # Check for observability integration -grep -rn "opentelemetry\|datadog\|sentry\|splunk\|elastic-apm" package.json 2>/dev/null +grep -rn "opentelemetry\|datadog\|sentry\|splunk\|elastic-apm" . --include="package.json" 2>/dev/null ``` Compare: count tool registrations (`server.tool` / `@mcp.tool`) vs structured logging references. If tools > 0 and structured logging = 0, flag it. @@ -538,13 +538,13 @@ Check for floating version references that enable rug-pull attacks. ```bash # @latest in any MCP config -grep -rniE '"@latest"' .mcp.json claude_desktop_config.json .cursor/mcp.json 2>/dev/null +grep -rniE '"@latest"' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null # npx without pinned version in MCP config commands -grep -rniE '"command"\s*:\s*"npx"' .mcp.json claude_desktop_config.json 2>/dev/null +grep -rniE '"command"\s*:\s*"npx"' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null # Verify packages have pinned versions (not @latest) -grep -rniE '@[a-z0-9-]+/[a-z0-9-]+' .mcp.json claude_desktop_config.json 2>/dev/null | grep -v '@[0-9]' | grep -v '@latest' +grep -rniE '@[a-z0-9-]+/[a-z0-9-]+' . --include=".mcp.json" --include="claude_desktop_config.json" 2>/dev/null | grep -v '@[0-9]' | grep -v '@latest' # Check if any MCP server hashes tool definitions (integrity verification) grep -rn "createHash\|sha256\|sha-256\|integrity\|checksum" --include="*.ts" --include="*.js" . | grep -iE "(tool|description|schema)" From e8c5e353154c98745a6c5b3d60736fc360b798f6 Mon Sep 17 00:00:00 2001 From: lorecraft-io Date: Sat, 4 Apr 2026 21:05:04 -0400 Subject: [PATCH 2/4] Security hardening: credentials.json gitignore, CI permissions, SHA-pin action - Add credentials.json to .gitignore (gap identified in security audit) - Add permissions:contents:read to lint.yml (least-privilege CI) - SHA-pin ludeeus/action-shellcheck to full commit hash (supply chain hardening) Co-Authored-By: claude-flow --- .github/workflows/lint.yml | 5 ++++- .gitignore | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4f4218b..0ae7dc4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,13 +6,16 @@ on: pull_request: branches: [main] +permissions: + contents: read + jobs: shellcheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run ShellCheck - uses: ludeeus/action-shellcheck@2.0.0 + uses: ludeeus/action-shellcheck@94e0aab03ca135d11a35e5bfc14e6746dc56e7e9 # v2.0.0 with: scandir: '.' severity: warning diff --git a/.gitignore b/.gitignore index 0e55127..bec89e7 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ CLAUDE.md *.cert *.p12 *.pfx +credentials.json # Node (defensive — step scripts may install deps) node_modules/ From e3cb192715875e51ade675030109ed972f60a6f9 Mon Sep 17 00:00:00 2001 From: lorecraft-io Date: Sat, 4 Apr 2026 22:03:20 -0400 Subject: [PATCH 3/4] Security hardening: pin SKILL_URL to SHA, sha256 verify, security CI, idempotent links - Pin SKILL_URL to commit SHA 7b449b6 (prevents rug-pull via mutable main branch) - Add sha256 checksum verification after SKILL.md download - Add .github/workflows/security.yml: strict ShellCheck, secret scanning, URL reachability - Fix step-7d link injection to be idempotent (check for [[project]] before appending) Co-Authored-By: claude-flow --- .github/workflows/security.yml | 59 ++++++++++++++++++++++++++++++++++ step-7/step-7d-wire-vault.sh | 12 +++---- step-9/step-9-install.sh | 23 ++++++++++++- 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/security.yml diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..3d25429 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,59 @@ +name: Security Checks + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '0 9 * * 1' # Weekly Monday 9am UTC + +permissions: + contents: read + +jobs: + shellcheck-strict: + name: ShellCheck (error severity) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run ShellCheck at error severity + uses: ludeeus/action-shellcheck@94e0aab03ca135d11a35e5bfc14e6746dc56e7e9 # v2.0.0 + with: + scandir: '.' + severity: error + ignore_paths: terminal-academy node_modules + + secret-scan: + name: Secret scanning + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Scan for hardcoded secrets + run: | + # Fail if real-looking API keys are found in tracked files + if git ls-files | xargs grep -lniE \ + "(sk-ant-api|ghp_[0-9A-Za-z]{36}|xoxb-[0-9A-Za-z-]+|AKIA[0-9A-Z]{16})" \ + 2>/dev/null | grep -v ".git"; then + echo "::error::Potential hardcoded secrets detected — see matches above" + exit 1 + fi + echo "No hardcoded secrets detected" + + download-url-check: + name: Verify pinned download URLs are reachable + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check SKILL_URL in step-9 + run: | + COMMIT=$(grep 'SKILL_COMMIT=' step-9/step-9-install.sh | head -1 | cut -d'"' -f2) + URL="https://raw.githubusercontent.com/lorecraft-io/cli-maxxing/${COMMIT}/step-9/safetycheck-skill/SKILL.md" + HTTP_STATUS=$(curl -o /dev/null -s -w "%{http_code}" "$URL") + if [ "$HTTP_STATUS" != "200" ]; then + echo "::error::Pinned SKILL_URL returned HTTP $HTTP_STATUS — commit SHA may be invalid" + exit 1 + fi + echo "SKILL_URL OK (HTTP 200) for commit $COMMIT" diff --git a/step-7/step-7d-wire-vault.sh b/step-7/step-7d-wire-vault.sh index 792f5de..2aff2e0 100755 --- a/step-7/step-7d-wire-vault.sh +++ b/step-7/step-7d-wire-vault.sh @@ -90,16 +90,14 @@ echo " Projects: $PROJECT_COUNT project folders" echo " Total: $TOTAL_NOTES notes" echo "" -# Auto-link orphan files to their parent project +# Auto-link orphan files to their parent project (idempotent — skips if link already present) info "Linking orphan files to parent projects..." LINK_COUNT=0 while IFS= read -r f; do - if ! grep -q '\[\[' "$f" 2>/dev/null; then - project=$(echo "$f" | sed "s|$VAULT_PATH/07-Projects/||" | cut -d'/' -f1) - if [ -n "$project" ]; then - printf "\n\n---\n[[%s]]\n" "$project" >> "$f" - LINK_COUNT=$((LINK_COUNT + 1)) - fi + project=$(echo "$f" | sed "s|$VAULT_PATH/07-Projects/||" | cut -d'/' -f1) + if [ -n "$project" ] && ! grep -qF "[[${project}]]" "$f" 2>/dev/null; then + printf "\n\n---\n[[%s]]\n" "$project" >> "$f" + LINK_COUNT=$((LINK_COUNT + 1)) fi done < <(find "$VAULT_PATH/07-Projects" -name '*.md') success "Linked orphan files to parent projects" diff --git a/step-9/step-9-install.sh b/step-9/step-9-install.sh index 3f4e443..171dc3b 100755 --- a/step-9/step-9-install.sh +++ b/step-9/step-9-install.sh @@ -94,7 +94,11 @@ verify_prerequisites() { install_skill() { SKILL_DIR="$HOME/.claude/skills/safetycheck" SKILL_FILE="$SKILL_DIR/SKILL.md" - SKILL_URL="https://raw.githubusercontent.com/lorecraft-io/cli-maxxing/main/step-9/safetycheck-skill/SKILL.md" + # Pinned to a specific commit SHA — prevents rug-pull via mutable branch ref + # To update: change the SHA to the new commit and update SKILL_SHA256 to match + SKILL_COMMIT="7b449b652d946a8eef9aca65f0c8e182b4fb80f7" + SKILL_URL="https://raw.githubusercontent.com/lorecraft-io/cli-maxxing/${SKILL_COMMIT}/step-9/safetycheck-skill/SKILL.md" + SKILL_SHA256="77e1ef1127fa35cd860925a652b96dd062ab080d438787b3bde348176597ab12" info "Creating skill directory..." mkdir -p "$SKILL_DIR" @@ -142,6 +146,23 @@ install_skill() { return fi + # Verify SHA-256 integrity — protects against corrupted download or tampered content + if command -v shasum &>/dev/null; then + ACTUAL_SHA=$(shasum -a 256 "$SKILL_FILE" | cut -d' ' -f1) + if [ "$ACTUAL_SHA" = "$SKILL_SHA256" ]; then + success "Skill file integrity verified (sha256 match)" + else + soft_fail "Skill file sha256 mismatch — file may be corrupt or tampered. Expected: ${SKILL_SHA256:0:16}..." + fi + elif command -v sha256sum &>/dev/null; then + ACTUAL_SHA=$(sha256sum "$SKILL_FILE" | cut -d' ' -f1) + if [ "$ACTUAL_SHA" = "$SKILL_SHA256" ]; then + success "Skill file integrity verified (sha256 match)" + else + soft_fail "Skill file sha256 mismatch — file may be corrupt or tampered. Expected: ${SKILL_SHA256:0:16}..." + fi + fi + # Verify the file contains expected content if grep -q "safetycheck" "$SKILL_FILE" 2>/dev/null; then success "Skill file content verified" From 88013fd9ef5b0723616c68f17dfaa46f9d3e722d Mon Sep 17 00:00:00 2001 From: lorecraft-io Date: Sat, 4 Apr 2026 22:16:51 -0400 Subject: [PATCH 4/4] Fix ShellCheck warnings blocking CI: SC2044, SC2034, SC2088 - step-final: convert for-loop-over-find to while-read (SC2044) - step-final: remove unused HC_ISSUES variable (SC2034) - update.sh: remove unused RED color variable (SC2034) - uninstall.sh: replace tilde with $HOME in message strings (SC2088) - step-1: replace tilde with $HOME in message string (SC2088) Co-Authored-By: claude-flow --- step-1/step-1-install.sh | 2 +- step-final/step-final-install.sh | 5 ++--- uninstall.sh | 4 ++-- update.sh | 1 - 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/step-1/step-1-install.sh b/step-1/step-1-install.sh index a074143..6156672 100755 --- a/step-1/step-1-install.sh +++ b/step-1/step-1-install.sh @@ -257,7 +257,7 @@ install_claude_code() { echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$SHELL_RC" success "Added ~/.local/bin to PATH in $SHELL_RC" else - success "~/.local/bin already in PATH" + success "$HOME/.local/bin already in PATH" fi # Install cbrain command (2ndBrain + skip-permissions) diff --git a/step-final/step-final-install.sh b/step-final/step-final-install.sh index 9d6ad6d..1fc3190 100755 --- a/step-final/step-final-install.sh +++ b/step-final/step-final-install.sh @@ -202,14 +202,14 @@ fi # ============================================================================= info "Checking for project-level statusLine overrides..." FOUND_OVERRIDES=0 -for PROJECT_SETTINGS in $(find "$HOME/Desktop" "$HOME/Documents" -maxdepth 5 -path "*/.claude/settings.json" -not -path "$HOME/.claude/settings.json" 2>/dev/null); do +while IFS= read -r PROJECT_SETTINGS; do if command -v jq &>/dev/null && jq -e '.statusLine' "$PROJECT_SETTINGS" &>/dev/null 2>&1; then jq 'del(.statusLine)' "$PROJECT_SETTINGS" > "${PROJECT_SETTINGS}.tmp" \ && mv "${PROJECT_SETTINGS}.tmp" "$PROJECT_SETTINGS" warn "Removed statusLine override from: $PROJECT_SETTINGS" FOUND_OVERRIDES=$((FOUND_OVERRIDES + 1)) fi -done +done < <(find "$HOME/Desktop" "$HOME/Documents" -maxdepth 5 -path "*/.claude/settings.json" -not -path "$HOME/.claude/settings.json" 2>/dev/null) if [ "$FOUND_OVERRIDES" -eq 0 ]; then success "No project-level statusLine overrides found" else @@ -234,7 +234,6 @@ esac HC_PASS=0 HC_FAIL=0 -HC_ISSUES="" # --- Shell aliases --- for alias_check in \ diff --git a/uninstall.sh b/uninstall.sh index 89c3ad3..57ffd1d 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -387,9 +387,9 @@ fi if grep -q '\.local/bin' "$SHELL_RC" 2>/dev/null; then sed -i.bak '/\.local\/bin/d' "$SHELL_RC" 2>/dev/null || true rm -f "${SHELL_RC}.bak" - success "~/.local/bin PATH entry removed from $SHELL_RC" + success "$HOME/.local/bin PATH entry removed from $SHELL_RC" else - skip "~/.local/bin PATH entry (not found in $SHELL_RC)" + skip "$HOME/.local/bin PATH entry (not found in $SHELL_RC)" fi # cbrain and cbraintg commands diff --git a/update.sh b/update.sh index d3c14fe..82dd94e 100755 --- a/update.sh +++ b/update.sh @@ -7,7 +7,6 @@ set -uo pipefail # Usage: curl -fsSL /update.sh | bash # ============================================================================= -RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m'