diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..6e3ed42e --- /dev/null +++ b/.clang-format @@ -0,0 +1,15 @@ +# ©AngelaMos | 2026 +# .clang-format +BasedOnStyle: LLVM +IndentWidth: 4 +TabWidth: 4 +UseTab: Never +ColumnLimit: 100 +AccessModifierOffset: -4 +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +SortIncludes: CaseSensitive +PointerAlignment: Left +SpaceBeforeParens: ControlStatements +BreakBeforeBraces: Attach diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index bffb1595..02c47721 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -68,6 +68,16 @@ jobs: - name: dlp-scanner type: ruff path: PROJECTS/intermediate/dlp-scanner + # Python (ruff) - Foundations + - name: hash-identifier + type: ruff + path: PROJECTS/foundations/hash-identifier + - name: http-headers-scanner + type: ruff + path: PROJECTS/foundations/http-headers-scanner + - name: password-manager + type: ruff + path: PROJECTS/foundations/password-manager # Biome (frontend) - name: bug-bounty-platform-frontend type: biome @@ -84,6 +94,21 @@ jobs: - name: encrypted-p2p-chat-frontend type: biome path: PROJECTS/advanced/encrypted-p2p-chat/frontend + - name: canary-token-generator-frontend + type: biome + path: PROJECTS/beginner/canary-token-generator/frontend + - name: ai-threat-detection-frontend + type: biome + path: PROJECTS/advanced/ai-threat-detection/frontend + - name: binary-analysis-tool-frontend + type: biome + path: PROJECTS/intermediate/binary-analysis-tool/frontend + - name: honeypot-network-frontend + type: biome + path: PROJECTS/advanced/honeypot-network/frontend + - name: monitor-the-situation-dashboard-frontend + type: biome + path: PROJECTS/advanced/monitor-the-situation-dashboard/frontend # Go - name: simple-vulnerability-scanner type: go @@ -94,10 +119,51 @@ jobs: - name: secrets-scanner type: go path: PROJECTS/intermediate/secrets-scanner + - name: canary-token-generator-backend + type: go + path: PROJECTS/beginner/canary-token-generator/backend + - name: systemd-persistence-scanner + type: go + path: PROJECTS/beginner/systemd-persistence-scanner + - name: sbom-generator-vulnerability-matcher + type: go + path: PROJECTS/intermediate/sbom-generator-vulnerability-matcher + - name: honeypot-network + type: go + path: PROJECTS/advanced/honeypot-network + - name: monitor-the-situation-dashboard-backend + type: go + path: PROJECTS/advanced/monitor-the-situation-dashboard/backend # Nim - name: credential-enumeration type: nim path: PROJECTS/intermediate/credential-enumeration + # Rust + - name: binary-analysis-tool-backend + type: rust + path: PROJECTS/intermediate/binary-analysis-tool/backend + # Crystal + - name: credential-rotation-enforcer + type: crystal + path: PROJECTS/intermediate/credential-rotation-enforcer + # V (Vlang) + - name: firewall-rule-engine + type: v + path: PROJECTS/beginner/firewall-rule-engine + # C++ + - name: hash-cracker + type: cpp + path: PROJECTS/beginner/hash-cracker + - name: simple-port-scanner + type: cpp + path: PROJECTS/beginner/simple-port-scanner + - name: network-traffic-analyzer-cpp + type: cpp + path: PROJECTS/beginner/network-traffic-analyzer/cpp + # Bash (shellcheck) + - name: linux-cis-hardening-auditor + type: bash + path: PROJECTS/beginner/linux-cis-hardening-auditor defaults: run: @@ -168,6 +234,61 @@ jobs: if: matrix.type == 'nim' run: nimble install -y nph + # Rust Setup + - name: Install Rust stable + if: matrix.type == 'rust' + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Cache Cargo registry and target + if: matrix.type == 'rust' + uses: Swatinem/rust-cache@v2 + with: + workspaces: "${{ matrix.path }} -> target" + + # Crystal Setup + - name: Install Crystal + if: matrix.type == 'crystal' + uses: crystal-lang/install-crystal@v1 + with: + crystal: latest + + - name: Cache shards + if: matrix.type == 'crystal' + uses: actions/cache@v4 + with: + path: ${{ matrix.path }}/lib + key: ${{ runner.os }}-shards-${{ matrix.name }}-${{ hashFiles(format('{0}/shard.lock', matrix.path)) }} + restore-keys: | + ${{ runner.os }}-shards-${{ matrix.name }}- + ${{ runner.os }}-shards- + + - name: Install shards + if: matrix.type == 'crystal' + run: shards install + + # V (Vlang) Setup + - name: Install V + if: matrix.type == 'v' + uses: vlang/setup-v@v1.4 + with: + check-latest: true + + # C++ Setup + - name: Install clang-format and cppcheck + if: matrix.type == 'cpp' + run: | + sudo apt-get update -qq + sudo apt-get install -y clang-format cppcheck + + # Bash Setup (shellcheck pre-installed on ubuntu-latest, but ensure latest) + - name: Install shellcheck + if: matrix.type == 'bash' + run: | + sudo apt-get update -qq + sudo apt-get install -y shellcheck + # Ruff Linting - name: Run ruff if: matrix.type == 'ruff' @@ -247,6 +368,152 @@ jobs: cat nim-output.txt continue-on-error: true + # Rust Linting + - name: Run cargo fmt and clippy + if: matrix.type == 'rust' + id: rust + run: | + RUST_OK=true + echo "Running cargo fmt --check..." + if cargo fmt -- --check > rust-output.txt 2>&1; then + echo "cargo fmt: no issues" + else + RUST_OK=false + echo "cargo fmt: formatting issues found" + fi + echo "Running cargo clippy..." + if cargo clippy --all-targets --all-features -- -D warnings >> rust-output.txt 2>&1; then + echo "cargo clippy: no issues" + else + RUST_OK=false + echo "cargo clippy: issues found" + fi + if [[ "$RUST_OK" == "true" ]]; then + echo "RUST_PASSED=true" >> $GITHUB_ENV + else + echo "RUST_PASSED=false" >> $GITHUB_ENV + fi + cat rust-output.txt + continue-on-error: true + + # Crystal Linting + - name: Run crystal format + ameba + compile check + if: matrix.type == 'crystal' + id: crystal + run: | + CRYSTAL_OK=true + echo "Running crystal tool format --check..." + if crystal tool format --check src/ spec/ > crystal-output.txt 2>&1; then + echo "crystal format: no issues" + else + CRYSTAL_OK=false + echo "crystal format: formatting issues found" + fi + echo "Running ameba..." + if bin/ameba src/ >> crystal-output.txt 2>&1; then + echo "ameba: no issues" + else + CRYSTAL_OK=false + echo "ameba: issues found" + fi + echo "Running crystal build --no-codegen..." + if crystal build --no-codegen src/cre.cr >> crystal-output.txt 2>&1; then + echo "crystal build: passed" + else + CRYSTAL_OK=false + echo "crystal build: failed" + fi + if [[ "$CRYSTAL_OK" == "true" ]]; then + echo "CRYSTAL_PASSED=true" >> $GITHUB_ENV + else + echo "CRYSTAL_PASSED=false" >> $GITHUB_ENV + fi + cat crystal-output.txt + continue-on-error: true + + # V Linting + - name: Run v fmt and v vet + if: matrix.type == 'v' + id: v + run: | + V_OK=true + echo "Running v fmt -diff src/..." + v fmt -diff src/ > v-output.txt 2>&1 || true + echo "Running v fmt -verify src/..." + if v fmt -verify src/ >> v-output.txt 2>&1; then + echo "v fmt: no issues" + else + V_OK=false + echo "v fmt: formatting issues found" + fi + echo "Running v vet src/..." + if v vet src/ >> v-output.txt 2>&1; then + echo "v vet: no issues" + else + V_OK=false + echo "v vet: issues found" + fi + if [[ "$V_OK" == "true" ]]; then + echo "V_PASSED=true" >> $GITHUB_ENV + else + echo "V_PASSED=false" >> $GITHUB_ENV + fi + cat v-output.txt + continue-on-error: true + + # C++ Linting + - name: Run clang-format and cppcheck + if: matrix.type == 'cpp' + id: cpp + run: | + CPP_OK=true + echo "Running clang-format check..." + FILES=$(find . \( -path ./build -o -path ./cmake-build -o -path ./node_modules -o -path ./.git \) -prune -o \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' \) -print 2>/dev/null) + if [ -n "$FILES" ]; then + if echo "$FILES" | xargs clang-format --dry-run --Werror > cpp-output.txt 2>&1; then + echo "clang-format: no issues" + else + CPP_OK=false + echo "clang-format: formatting issues found" + fi + else + echo "clang-format: no C++ files found" > cpp-output.txt + fi + echo "Running cppcheck..." + if cppcheck --enable=warning,style,performance,portability --error-exitcode=1 --suppress=missingIncludeSystem --suppress=normalCheckLevelMaxBranches -i build -i cmake-build -q . >> cpp-output.txt 2>&1; then + echo "cppcheck: no issues" + else + CPP_OK=false + echo "cppcheck: issues found" + fi + if [[ "$CPP_OK" == "true" ]]; then + echo "CPP_PASSED=true" >> $GITHUB_ENV + else + echo "CPP_PASSED=false" >> $GITHUB_ENV + fi + cat cpp-output.txt + continue-on-error: true + + # Bash Linting + - name: Run shellcheck + if: matrix.type == 'bash' + id: bash + run: | + echo "Running shellcheck..." + FILES=$(find . -name '*.sh' -not -path '*/.venv/*' -not -path '*/node_modules/*' 2>/dev/null || true) + if [ -z "$FILES" ]; then + echo "shellcheck: no .sh files found" > bash-output.txt + echo "BASH_PASSED=true" >> $GITHUB_ENV + elif echo "$FILES" | xargs shellcheck > bash-output.txt 2>&1; then + echo "BASH_PASSED=true" >> $GITHUB_ENV + echo "shellcheck: no issues" + else + echo "BASH_PASSED=false" >> $GITHUB_ENV + echo "shellcheck: issues found" + fi + cat bash-output.txt + continue-on-error: true + # Create Summary for Ruff - name: Create Ruff Lint Summary if: matrix.type == 'ruff' @@ -371,6 +638,151 @@ jobs: fi } >> $GITHUB_STEP_SUMMARY + # Create Summary for Rust + - name: Create Rust Lint Summary + if: matrix.type == 'rust' + run: | + { + echo "## Lint Results: ${{ matrix.name }}" + echo '' + if [[ "${{ env.RUST_PASSED }}" == "true" ]]; then + echo '### cargo fmt + clippy: **Passed**' + echo 'No Rust issues found.' + else + echo '### cargo fmt + clippy: **Issues Found**' + echo '
View output' + echo '' + echo '```' + head -100 rust-output.txt + echo '```' + echo '
' + fi + echo '' + if [[ "${{ env.RUST_PASSED }}" == "true" ]]; then + echo '---' + echo '### All checks passed!' + else + echo '---' + echo '### Review the issues above' + fi + } >> $GITHUB_STEP_SUMMARY + + # Create Summary for Crystal + - name: Create Crystal Lint Summary + if: matrix.type == 'crystal' + run: | + { + echo "## Lint Results: ${{ matrix.name }}" + echo '' + if [[ "${{ env.CRYSTAL_PASSED }}" == "true" ]]; then + echo '### crystal format + ameba + build: **Passed**' + echo 'No Crystal issues found.' + else + echo '### crystal format + ameba + build: **Issues Found**' + echo '
View output' + echo '' + echo '```' + head -100 crystal-output.txt + echo '```' + echo '
' + fi + echo '' + if [[ "${{ env.CRYSTAL_PASSED }}" == "true" ]]; then + echo '---' + echo '### All checks passed!' + else + echo '---' + echo '### Review the issues above' + fi + } >> $GITHUB_STEP_SUMMARY + + # Create Summary for V + - name: Create V Lint Summary + if: matrix.type == 'v' + run: | + { + echo "## Lint Results: ${{ matrix.name }}" + echo '' + if [[ "${{ env.V_PASSED }}" == "true" ]]; then + echo '### v fmt + v vet: **Passed**' + echo 'No V issues found.' + else + echo '### v fmt + v vet: **Issues Found**' + echo '
View output' + echo '' + echo '```' + head -100 v-output.txt + echo '```' + echo '
' + fi + echo '' + if [[ "${{ env.V_PASSED }}" == "true" ]]; then + echo '---' + echo '### All checks passed!' + else + echo '---' + echo '### Review the issues above' + fi + } >> $GITHUB_STEP_SUMMARY + + # Create Summary for C++ + - name: Create C++ Lint Summary + if: matrix.type == 'cpp' + run: | + { + echo "## Lint Results: ${{ matrix.name }}" + echo '' + if [[ "${{ env.CPP_PASSED }}" == "true" ]]; then + echo '### clang-format + cppcheck: **Passed**' + echo 'No C++ issues found.' + else + echo '### clang-format + cppcheck: **Issues Found**' + echo '
View output' + echo '' + echo '```' + head -100 cpp-output.txt + echo '```' + echo '
' + fi + echo '' + if [[ "${{ env.CPP_PASSED }}" == "true" ]]; then + echo '---' + echo '### All checks passed!' + else + echo '---' + echo '### Review the issues above' + fi + } >> $GITHUB_STEP_SUMMARY + + # Create Summary for Bash + - name: Create Bash Lint Summary + if: matrix.type == 'bash' + run: | + { + echo "## Lint Results: ${{ matrix.name }}" + echo '' + if [[ "${{ env.BASH_PASSED }}" == "true" ]]; then + echo '### shellcheck: **Passed**' + echo 'No shell issues found.' + else + echo '### shellcheck: **Issues Found**' + echo '
View output' + echo '' + echo '```' + head -100 bash-output.txt + echo '```' + echo '
' + fi + echo '' + if [[ "${{ env.BASH_PASSED }}" == "true" ]]; then + echo '---' + echo '### All checks passed!' + else + echo '---' + echo '### Review the issues above' + fi + } >> $GITHUB_STEP_SUMMARY + # Exit with proper status - name: Check lint status run: | @@ -394,5 +806,30 @@ jobs: echo "Nim lint checks failed" exit 1 fi + elif [[ "${{ matrix.type }}" == "rust" ]]; then + if [[ "${{ env.RUST_PASSED }}" == "false" ]]; then + echo "Rust lint checks failed" + exit 1 + fi + elif [[ "${{ matrix.type }}" == "crystal" ]]; then + if [[ "${{ env.CRYSTAL_PASSED }}" == "false" ]]; then + echo "Crystal lint checks failed" + exit 1 + fi + elif [[ "${{ matrix.type }}" == "v" ]]; then + if [[ "${{ env.V_PASSED }}" == "false" ]]; then + echo "V lint checks failed" + exit 1 + fi + elif [[ "${{ matrix.type }}" == "cpp" ]]; then + if [[ "${{ env.CPP_PASSED }}" == "false" ]]; then + echo "C++ lint checks failed" + exit 1 + fi + elif [[ "${{ matrix.type }}" == "bash" ]]; then + if [[ "${{ env.BASH_PASSED }}" == "false" ]]; then + echo "Bash lint checks failed" + exit 1 + fi fi echo "All lint checks passed" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 20efe34a..ec12e31e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -84,6 +84,37 @@ repos: files: ^PROJECTS/advanced/ai-threat-detection/backend/ exclude: (\.venv|__pycache__|\.pytest_cache)/ + - id: ruff + name: ruff check (dlp-scanner) + args: [--fix, --exit-non-zero-on-fix] + files: ^PROJECTS/intermediate/dlp-scanner/ + exclude: (\.venv|__pycache__|\.pytest_cache)/ + + - id: ruff + name: ruff check (linux-ebpf-security-tracer) + args: [--fix, --exit-non-zero-on-fix] + files: ^PROJECTS/beginner/linux-ebpf-security-tracer/ + exclude: (\.venv|__pycache__|\.pytest_cache)/ + + # Foundations projects + - id: ruff + name: ruff check (hash-identifier) + args: [--fix, --exit-non-zero-on-fix] + files: ^PROJECTS/foundations/hash-identifier/ + exclude: (\.venv|__pycache__|\.pytest_cache)/ + + - id: ruff + name: ruff check (http-headers-scanner) + args: [--fix, --exit-non-zero-on-fix] + files: ^PROJECTS/foundations/http-headers-scanner/ + exclude: (\.venv|__pycache__|\.pytest_cache)/ + + - id: ruff + name: ruff check (password-manager) + args: [--fix, --exit-non-zero-on-fix] + files: ^PROJECTS/foundations/password-manager/ + exclude: (\.venv|__pycache__|\.pytest_cache)/ + # Go golangci-lint Checks - repo: local @@ -112,6 +143,48 @@ repos: types: [go] pass_filenames: false + - id: golangci-lint-canary-token-generator + name: golangci-lint (canary-token-generator backend) + entry: bash -c 'cd PROJECTS/beginner/canary-token-generator/backend && golangci-lint run --fix' + language: system + files: ^PROJECTS/beginner/canary-token-generator/backend/ + types: [go] + pass_filenames: false + + - id: golangci-lint-systemd-persistence-scanner + name: golangci-lint (systemd-persistence-scanner) + entry: bash -c 'cd PROJECTS/beginner/systemd-persistence-scanner && golangci-lint run --fix' + language: system + files: ^PROJECTS/beginner/systemd-persistence-scanner/ + types: [go] + pass_filenames: false + + - id: golangci-lint-sbom-generator + name: golangci-lint (sbom-generator-vulnerability-matcher) + entry: bash -c 'cd PROJECTS/intermediate/sbom-generator-vulnerability-matcher && golangci-lint run --fix' + language: system + files: ^PROJECTS/intermediate/sbom-generator-vulnerability-matcher/ + exclude: ^PROJECTS/intermediate/sbom-generator-vulnerability-matcher/testdata/ + types: [go] + pass_filenames: false + + - id: golangci-lint-honeypot-network + name: golangci-lint (honeypot-network) + entry: bash -c 'cd PROJECTS/advanced/honeypot-network && golangci-lint run --fix' + language: system + files: ^PROJECTS/advanced/honeypot-network/ + exclude: ^PROJECTS/advanced/honeypot-network/frontend/ + types: [go] + pass_filenames: false + + - id: golangci-lint-monitor-the-situation-dashboard + name: golangci-lint (monitor-the-situation-dashboard backend) + entry: bash -c 'cd PROJECTS/advanced/monitor-the-situation-dashboard/backend && golangci-lint run --fix' + language: system + files: ^PROJECTS/advanced/monitor-the-situation-dashboard/backend/ + types: [go] + pass_filenames: false + # Biome Frontend Checks - repo: local hooks: @@ -150,6 +223,41 @@ repos: files: ^PROJECTS/advanced/encrypted-p2p-chat/frontend/src/ pass_filenames: false + - id: biome-canary-token-generator + name: biome check (canary-token-generator frontend) + entry: bash -c 'cd PROJECTS/beginner/canary-token-generator/frontend && npx @biomejs/biome check .' + language: system + files: ^PROJECTS/beginner/canary-token-generator/frontend/src/ + pass_filenames: false + + - id: biome-ai-threat-detection + name: biome check (ai-threat-detection frontend) + entry: bash -c 'cd PROJECTS/advanced/ai-threat-detection/frontend && npx @biomejs/biome check .' + language: system + files: ^PROJECTS/advanced/ai-threat-detection/frontend/src/ + pass_filenames: false + + - id: biome-binary-analysis-tool + name: biome check (binary-analysis-tool frontend) + entry: bash -c 'cd PROJECTS/intermediate/binary-analysis-tool/frontend && npx @biomejs/biome check .' + language: system + files: ^PROJECTS/intermediate/binary-analysis-tool/frontend/src/ + pass_filenames: false + + - id: biome-honeypot-network + name: biome check (honeypot-network frontend) + entry: bash -c 'cd PROJECTS/advanced/honeypot-network/frontend && npx @biomejs/biome check .' + language: system + files: ^PROJECTS/advanced/honeypot-network/frontend/src/ + pass_filenames: false + + - id: biome-monitor-the-situation-dashboard + name: biome check (monitor-the-situation-dashboard frontend) + entry: bash -c 'cd PROJECTS/advanced/monitor-the-situation-dashboard/frontend && npx @biomejs/biome check .' + language: system + files: ^PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/ + pass_filenames: false + # Nim nph Checks - repo: local hooks: @@ -160,6 +268,130 @@ repos: files: ^PROJECTS/intermediate/credential-enumeration/src/ pass_filenames: false + # Rust Checks (cargo fmt + clippy) + - repo: local + hooks: + - id: cargo-fmt-binary-analysis-tool + name: cargo fmt (binary-analysis-tool backend) + entry: bash -c 'cd PROJECTS/intermediate/binary-analysis-tool/backend && cargo fmt -- --check' + language: system + files: ^PROJECTS/intermediate/binary-analysis-tool/backend/ + types: [rust] + pass_filenames: false + + - id: cargo-clippy-binary-analysis-tool + name: cargo clippy (binary-analysis-tool backend) + entry: bash -c 'cd PROJECTS/intermediate/binary-analysis-tool/backend && cargo clippy --all-targets --all-features -- -D warnings' + language: system + files: ^PROJECTS/intermediate/binary-analysis-tool/backend/ + types: [rust] + pass_filenames: false + + # Crystal Checks (format + ameba + compile) + - repo: local + hooks: + - id: crystal-format-credential-rotation-enforcer + name: crystal format check (credential-rotation-enforcer) + entry: bash -c 'cd PROJECTS/intermediate/credential-rotation-enforcer && crystal tool format --check src/ spec/' + language: system + files: ^PROJECTS/intermediate/credential-rotation-enforcer/ + types_or: [crystal] + pass_filenames: false + + - id: ameba-credential-rotation-enforcer + name: ameba (credential-rotation-enforcer) + entry: bash -c 'cd PROJECTS/intermediate/credential-rotation-enforcer && bin/ameba src/' + language: system + files: ^PROJECTS/intermediate/credential-rotation-enforcer/ + types_or: [crystal] + pass_filenames: false + + - id: crystal-build-check-credential-rotation-enforcer + name: crystal compile check (credential-rotation-enforcer) + entry: bash -c 'cd PROJECTS/intermediate/credential-rotation-enforcer && crystal build --no-codegen src/cre.cr' + language: system + files: ^PROJECTS/intermediate/credential-rotation-enforcer/ + types_or: [crystal] + pass_filenames: false + + # V (Vlang) Checks + - repo: local + hooks: + - id: v-fmt-firewall-rule-engine + name: v fmt (firewall-rule-engine) + entry: bash -c 'cd PROJECTS/beginner/firewall-rule-engine && v fmt -verify src/' + language: system + files: ^PROJECTS/beginner/firewall-rule-engine/src/ + pass_filenames: false + + - id: v-vet-firewall-rule-engine + name: v vet (firewall-rule-engine) + entry: bash -c 'cd PROJECTS/beginner/firewall-rule-engine && v vet src/' + language: system + files: ^PROJECTS/beginner/firewall-rule-engine/src/ + pass_filenames: false + + # C++ Checks (clang-format + cppcheck) + - repo: local + hooks: + - id: clang-format-hash-cracker + name: clang-format (hash-cracker) + entry: bash -c 'cd PROJECTS/beginner/hash-cracker && find . \( -path ./build -o -path ./cmake-build -o -path ./.git \) -prune -o \( -name "*.cpp" -o -name "*.hpp" -o -name "*.h" \) -print 2>/dev/null | xargs -r clang-format --dry-run --Werror' + language: system + files: ^PROJECTS/beginner/hash-cracker/ + types_or: [c++, c] + pass_filenames: false + + - id: cppcheck-hash-cracker + name: cppcheck (hash-cracker) + entry: bash -c 'cd PROJECTS/beginner/hash-cracker && cppcheck --enable=warning,style,performance,portability --error-exitcode=1 --suppress=missingIncludeSystem --suppress=normalCheckLevelMaxBranches -i build -i cmake-build -q .' + language: system + files: ^PROJECTS/beginner/hash-cracker/ + types_or: [c++, c] + pass_filenames: false + + - id: clang-format-simple-port-scanner + name: clang-format (simple-port-scanner) + entry: bash -c 'cd PROJECTS/beginner/simple-port-scanner && find . \( -path ./build -o -path ./cmake-build -o -path ./.git \) -prune -o \( -name "*.cpp" -o -name "*.hpp" -o -name "*.h" \) -print 2>/dev/null | xargs -r clang-format --dry-run --Werror' + language: system + files: ^PROJECTS/beginner/simple-port-scanner/ + types_or: [c++, c] + pass_filenames: false + + - id: cppcheck-simple-port-scanner + name: cppcheck (simple-port-scanner) + entry: bash -c 'cd PROJECTS/beginner/simple-port-scanner && cppcheck --enable=warning,style,performance,portability --error-exitcode=1 --suppress=missingIncludeSystem --suppress=normalCheckLevelMaxBranches -i build -i cmake-build -q .' + language: system + files: ^PROJECTS/beginner/simple-port-scanner/ + types_or: [c++, c] + pass_filenames: false + + - id: clang-format-network-traffic-analyzer-cpp + name: clang-format (network-traffic-analyzer/cpp) + entry: bash -c 'cd PROJECTS/beginner/network-traffic-analyzer/cpp && find . \( -path ./build -o -path ./cmake-build -o -path ./.git \) -prune -o \( -name "*.cpp" -o -name "*.hpp" -o -name "*.h" \) -print 2>/dev/null | xargs -r clang-format --dry-run --Werror' + language: system + files: ^PROJECTS/beginner/network-traffic-analyzer/cpp/ + types_or: [c++, c] + pass_filenames: false + + - id: cppcheck-network-traffic-analyzer-cpp + name: cppcheck (network-traffic-analyzer/cpp) + entry: bash -c 'cd PROJECTS/beginner/network-traffic-analyzer/cpp && cppcheck --enable=warning,style,performance,portability --error-exitcode=1 --suppress=missingIncludeSystem --suppress=normalCheckLevelMaxBranches -i build -i cmake-build -q .' + language: system + files: ^PROJECTS/beginner/network-traffic-analyzer/cpp/ + types_or: [c++, c] + pass_filenames: false + + # Bash (shellcheck) + - repo: local + hooks: + - id: shellcheck-linux-cis-hardening-auditor + name: shellcheck (linux-cis-hardening-auditor) + entry: bash -c 'find PROJECTS/beginner/linux-cis-hardening-auditor -name "*.sh" -not -path "*/.venv/*" | xargs -r shellcheck' + language: system + files: ^PROJECTS/beginner/linux-cis-hardening-auditor/.*\.sh$ + pass_filenames: false + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/components/event-feed.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/components/event-feed.tsx index c7799aaf..cacfc6af 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/components/event-feed.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/components/event-feed.tsx @@ -2,8 +2,8 @@ // event-feed.tsx import { useWebSocketStore } from '@/core/lib/websocket.store' -import { ServiceBadge } from './service-badge' import styles from './event-feed.module.scss' +import { ServiceBadge } from './service-badge' const MAX_VISIBLE = 15 diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/components/service-badge.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/components/service-badge.tsx index 04d20088..72bba415 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/components/service-badge.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/components/service-badge.tsx @@ -9,9 +9,5 @@ interface ServiceBadgeProps { } export function ServiceBadge({ service }: ServiceBadgeProps) { - return ( - - {service.toUpperCase()} - - ) + return {service.toUpperCase()} } diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/core/app/shell.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/core/app/shell.tsx index c2fbefca..4e976a1e 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/core/app/shell.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/core/app/shell.tsx @@ -52,9 +52,7 @@ export function Shell() {
LINK - + {connected ? 'ACTIVE' : 'DOWN'}
diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/pages/attackers/detail.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/pages/attackers/detail.tsx index 904c99e2..32c1d76d 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/pages/attackers/detail.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/pages/attackers/detail.tsx @@ -57,9 +57,7 @@ export function AttackerDetailPage() {
THREAT SCORE - + {attacker.threat_score}
diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/pages/attackers/index.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/pages/attackers/index.tsx index b5823ea3..69cdacee 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/pages/attackers/index.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/pages/attackers/index.tsx @@ -34,10 +34,7 @@ export function AttackersPage() { {attackers?.map((a) => ( - + {a.ip} diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/pages/dashboard/index.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/pages/dashboard/index.tsx index 772921c2..67188e5b 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/pages/dashboard/index.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/pages/dashboard/index.tsx @@ -113,11 +113,7 @@ export function DashboardPage() { axisLine={false} /> - + @@ -143,28 +139,24 @@ export function DashboardPage() {

Top Usernames

- {credentials.top_usernames - .slice(0, TOP_CREDS_LIMIT) - .map((u) => ( -
- {u.value} - {u.count} -
- ))} + {credentials.top_usernames.slice(0, TOP_CREDS_LIMIT).map((u) => ( +
+ {u.value} + {u.count} +
+ ))}

Top Passwords

- {credentials.top_passwords - .slice(0, TOP_CREDS_LIMIT) - .map((p) => ( -
- {p.value} - {p.count} -
- ))} + {credentials.top_passwords.slice(0, TOP_CREDS_LIMIT).map((p) => ( +
+ {p.value} + {p.count} +
+ ))}
diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/pages/events/index.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/pages/events/index.tsx index 4d15a83a..c752a4b0 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/pages/events/index.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/pages/events/index.tsx @@ -10,10 +10,7 @@ const PAGE_SIZE = 50 export function EventsPage() { const [ipFilter, setIpFilter] = useState('') - const { data: events, isLoading } = useEvents( - PAGE_SIZE, - ipFilter || undefined - ) + const { data: events, isLoading } = useEvents(PAGE_SIZE, ipFilter || undefined) return (
diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/pages/intel/index.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/pages/intel/index.tsx index 98b73645..23d2ec21 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/pages/intel/index.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/pages/intel/index.tsx @@ -27,24 +27,16 @@ export function IntelPage() { const res = await apiClient.get(API_ENDPOINTS.IOCS.EXPORT_STIX, { responseType: 'text', }) - downloadBlob( - res.data as string, - 'hive-iocs.stix.json', - 'application/json' - ) + downloadBlob(res.data as string, 'hive-iocs.stix.json', 'application/json') } async function exportBlocklist(format: string) { - const res = await apiClient.get( - API_ENDPOINTS.IOCS.EXPORT_BLOCKLIST, - { params: { format }, responseType: 'text' } - ) + const res = await apiClient.get(API_ENDPOINTS.IOCS.EXPORT_BLOCKLIST, { + params: { format }, + responseType: 'text', + }) const ext = format === 'csv' ? '.csv' : '.txt' - downloadBlob( - res.data as string, - `hive-blocklist${ext}`, - 'text/plain' - ) + downloadBlob(res.data as string, `hive-blocklist${ext}`, 'text/plain') } return ( @@ -52,18 +44,12 @@ export function IntelPage() {

Intel

- - THREAT INTELLIGENCE PRODUCTS - + THREAT INTELLIGENCE PRODUCTS
EXPORT - {BLOCKLIST_FORMATS.map((fmt) => ( @@ -103,12 +89,8 @@ export function IntelPage() { {ioc.confidence}% {ioc.sight_count} {ioc.source} - - {new Date(ioc.first_seen).toLocaleDateString()} - - - {new Date(ioc.last_seen).toLocaleDateString()} - + {new Date(ioc.first_seen).toLocaleDateString()} + {new Date(ioc.last_seen).toLocaleDateString()} ))} @@ -120,25 +102,20 @@ export function IntelPage() { className={styles.pageBtn} disabled={offset === 0} onClick={() => - setOffset( - Math.max(0, offset - PAGINATION.DEFAULT_LIMIT) - ) + setOffset(Math.max(0, offset - PAGINATION.DEFAULT_LIMIT)) } > ◀ PREV {offset + 1}– - {Math.min(offset + PAGINATION.DEFAULT_LIMIT, total)} OF{' '} - {total} + {Math.min(offset + PAGINATION.DEFAULT_LIMIT, total)} OF {total} diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/pages/mitre/index.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/pages/mitre/index.tsx index 86e7b81e..ab8768dc 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/pages/mitre/index.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/pages/mitre/index.tsx @@ -29,9 +29,7 @@ export function MitrePage() { const { data: techniques } = useMitreTechniques() const { data: heatmap } = useMitreHeatmap() - const countMap = new Map( - heatmap?.map((h) => [h.technique_id, h.count]) - ) + const countMap = new Map(heatmap?.map((h) => [h.technique_id, h.count])) const byTactic = new Map() for (const t of techniques ?? []) { @@ -51,9 +49,7 @@ export function MitrePage() { INTENSITY {HEAT_THRESHOLDS.map((t, i) => ( - + {t}+ ))} @@ -66,9 +62,7 @@ export function MitrePage() { return (
-

- {tactic.replace(/-/g, ' ')} -

+

{tactic.replace(/-/g, ' ')}

{techs.map((t) => { const count = countMap.get(t.id) ?? 0 @@ -83,9 +77,7 @@ export function MitrePage() { {t.id} {t.name} {count > 0 && ( - - {count} - + {count} )}
) diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/pages/sessions/detail.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/pages/sessions/detail.tsx index 8ddb14a6..3c2c541b 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/pages/sessions/detail.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/pages/sessions/detail.tsx @@ -44,9 +44,7 @@ export function SessionDetailPage() { ← SESSIONS -

- SESSION {session.id.slice(0, 8)} -

+

SESSION {session.id.slice(0, 8)}

{rows.map((row) => ( diff --git a/PROJECTS/advanced/honeypot-network/frontend/src/pages/sessions/index.tsx b/PROJECTS/advanced/honeypot-network/frontend/src/pages/sessions/index.tsx index cc30599c..9d1829f0 100644 --- a/PROJECTS/advanced/honeypot-network/frontend/src/pages/sessions/index.tsx +++ b/PROJECTS/advanced/honeypot-network/frontend/src/pages/sessions/index.tsx @@ -52,10 +52,7 @@ export function SessionsPage() { return ( - + {s.id.slice(0, 8)} @@ -67,9 +64,7 @@ export function SessionsPage() { {s.command_count} {s.threat_score} {new Date(s.started_at).toLocaleString()} - - {duration !== null ? `${duration}s` : 'active'} - + {duration !== null ? `${duration}s` : 'active'} ) })} @@ -81,15 +76,12 @@ export function SessionsPage() { type="button" className={styles.pageBtn} disabled={offset === 0} - onClick={() => - setOffset(Math.max(0, offset - PAGE_SIZE)) - } + onClick={() => setOffset(Math.max(0, offset - PAGE_SIZE))} > ◀ PREV - {offset + 1}–{Math.min(offset + PAGE_SIZE, total)}{' '} - OF {total} + {offset + 1}–{Math.min(offset + PAGE_SIZE, total)} OF {total}
diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/.ameba.yml b/PROJECTS/intermediate/credential-rotation-enforcer/.ameba.yml new file mode 100644 index 00000000..d8a14688 --- /dev/null +++ b/PROJECTS/intermediate/credential-rotation-enforcer/.ameba.yml @@ -0,0 +1,16 @@ +# ©AngelaMos | 2026 +# .ameba.yml +# +# Disabled rules document intentional patterns in this codebase +# - Naming/BlockParameterName: idiomatic Crystal uses short block params like |c|, |b| +# - Lint/NotNil: .not_nil! used as explicit runtime contract assertion after upstream +# validation; raising NilAssertionError is the desired crash mode for misconfiguration +# Raised thresholds match the natural shape of dispatch/subscriber handlers +Naming/BlockParameterName: + Enabled: false + +Lint/NotNil: + Enabled: false + +Metrics/CyclomaticComplexity: + MaxComplexity: 20 diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/shard.lock b/PROJECTS/intermediate/credential-rotation-enforcer/shard.lock index 4da0ce31..5c86ac70 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/shard.lock +++ b/PROJECTS/intermediate/credential-rotation-enforcer/shard.lock @@ -1,5 +1,9 @@ version: 2.0 shards: + ameba: + git: https://github.com/crystal-ameba/ameba.git + version: 1.6.4 + db: git: https://github.com/crystal-lang/crystal-db.git version: 0.11.0 diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/shard.yml b/PROJECTS/intermediate/credential-rotation-enforcer/shard.yml index 0afcc30e..56f75bbc 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/shard.yml +++ b/PROJECTS/intermediate/credential-rotation-enforcer/shard.yml @@ -33,3 +33,6 @@ development_dependencies: webmock: github: manastech/webmock.cr version: ~> 0.9 + ameba: + github: crystal-ameba/ameba + version: ~> 1.6.4 diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/aws/signer.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/aws/signer.cr index 5e4c8bdd..8d17acd8 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/aws/signer.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/aws/signer.cr @@ -79,7 +79,7 @@ module CRE::Aws end private def canonical_query(query : String?) : String - return "" unless query && !query.empty? + return "" if query.nil? || query.empty? params = [] of {String, String} query.split('&') do |pair| eq = pair.index('=') @@ -99,7 +99,7 @@ module CRE::Aws private def canonical_headers_and_list(headers : HTTP::Headers) : {String, String} sorted = headers.to_a.map { |name, values| {name.downcase, values.first.strip.gsub(/\s+/, " ")} - }.sort_by { |entry| entry[0] } + }.sort_by! { |entry| entry[0] } canonical = sorted.map { |k, v| "#{k}:#{v}\n" }.join list = sorted.map(&.[0]).join(';') diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/cli/commands/check.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/cli/commands/check.cr index 2dc78c15..c8078f6b 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/cli/commands/check.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/cli/commands/check.cr @@ -32,7 +32,7 @@ module CRE::Cli::Commands CRE::Policy::Evaluator.new(bus, persist).evaluate_all sleep 0.1.seconds - violations = drain(ch).select(&.is_a?(CRE::Events::PolicyViolation)).map(&.as(CRE::Events::PolicyViolation)) + violations = drain(ch).select(CRE::Events::PolicyViolation).map(&.as(CRE::Events::PolicyViolation)) bus.stop persist.close diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/demo/tui_demo.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/demo/tui_demo.cr index dc0d0212..77b46b80 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/demo/tui_demo.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/demo/tui_demo.cr @@ -19,7 +19,7 @@ module CRE::Demo bus.run tui.start - script_fiber = spawn do + spawn do run_script(bus, seconds) end diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/engine/rotation_orchestrator.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/engine/rotation_orchestrator.cr index 9fa682d9..bc489b9c 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/engine/rotation_orchestrator.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/engine/rotation_orchestrator.cr @@ -59,7 +59,7 @@ module CRE::Engine @persistence.rotations.update_state(rotation_id, Persistence::RotationState::Applying) @bus.publish Events::RotationStepCompleted.new(c.id, rotation_id, :generate) - current_step = :apply + current_step = :apply # ameba:disable Lint/UselessAssign — read in rescue @bus.publish Events::RotationStepStarted.new(c.id, rotation_id, :apply) rotator.apply(c, new_secret) @persistence.rotations.update_state(rotation_id, Persistence::RotationState::Verifying) @@ -83,8 +83,8 @@ module CRE::Engine if (ns = new_secret) && (current_step == :apply || current_step == :verify) begin rotator.rollback_apply(c, ns) - rescue rb - Log.error(exception: rb) { "rollback_apply failed for credential #{c.id}" } + rescue error + Log.error(exception: error) { "rollback_apply failed for credential #{c.id}" } end end finalize_failure(c, rotation_id, current_step, ex) diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/postgres/postgres_persistence.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/postgres/postgres_persistence.cr index 661dc7a9..213adbe3 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/postgres/postgres_persistence.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/postgres/postgres_persistence.cr @@ -40,11 +40,11 @@ module CRE::Persistence::Postgres @audit ||= AuditRepo.new(@db) end - def transaction(&block : ->) : Nil + def transaction(& : ->) : Nil @db.transaction { yield } end - def with_advisory_lock(key : Int64, &block : ->) : Nil + def with_advisory_lock(key : Int64, & : ->) : Nil @db.transaction do |tx| tx.connection.exec("SELECT pg_advisory_xact_lock($1)", key) yield diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/sqlite/sqlite_persistence.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/sqlite/sqlite_persistence.cr index 58c61c69..076459b1 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/sqlite/sqlite_persistence.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/sqlite/sqlite_persistence.cr @@ -48,11 +48,11 @@ module CRE::Persistence::Sqlite @audit ||= AuditRepo.new(@db) end - def transaction(&block : ->) : Nil + def transaction(& : ->) : Nil @db.transaction { yield } end - def with_advisory_lock(key : Int64, &block : ->) : Nil + def with_advisory_lock(key : Int64, & : ->) : Nil _ = key # SQLite is single-process; the mutex is sufficient @mutex.synchronize { yield } end diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/policy/dsl.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/policy/dsl.cr index ff7c4b71..47adc99e 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/policy/dsl.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/policy/dsl.cr @@ -25,7 +25,7 @@ module CRE::Policy::Dsl # `enforce :rotate_immediatly` fail at compile time. Splat-symbol args # (`notify_via :telegram, :structured_log`) are validated at policy # registration time and raise `BuilderError` on typos. - def policy(name : String, &block) + def policy(name : String, &) builder = CRE::Policy::Builder.new(name) with builder yield CRE::Policy::REGISTRY << builder.build diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/policy/evaluator.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/policy/evaluator.cr index 11cc25cc..1d4d2d43 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/policy/evaluator.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/policy/evaluator.cr @@ -54,7 +54,7 @@ module CRE::Policy return if @policies.empty? seen = Set(UUID).new - @policies.group_by(&.max_age).each do |max_age, policies_with_age| + @policies.group_by(&.max_age).each do |max_age, _| @persistence.credentials.overdue(now, max_age).each do |c| next if seen.includes?(c.id) seen << c.id diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/rotators/env_file.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/rotators/env_file.cr index e33a015a..8ec6ee3b 100644 --- a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/rotators/env_file.cr +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/rotators/env_file.cr @@ -50,7 +50,7 @@ module CRE::Rotators pending = pending_path(path) existing = File.exists?(path) ? File.read(path) : "" - lines = existing.lines(chomp: true).reject { |line| line.strip.starts_with?("#{key}=") } + lines = existing.lines(chomp: true).reject(&.strip.starts_with?("#{key}=")) new_value = String.new(s.ciphertext) lines << "#{key}=#{new_value}" diff --git a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/.golangci.yml b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/.golangci.yml index 794b0097..c438ea7c 100644 --- a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/.golangci.yml +++ b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/.golangci.yml @@ -1,31 +1,39 @@ # ©AngelaMos | 2026 # .golangci.yml +version: "2" run: timeout: 5m linters: + default: none enable: - errcheck - govet - staticcheck - unused - - gosimple - ineffassign - - typecheck - - gofmt - gocritic - gosec - misspell - unconvert - unparam - prealloc - -linters-settings: - gocritic: - enabled-tags: - - diagnostic - - performance - gosec: - excludes: - - G304 + settings: + errcheck: + exclude-functions: + - fmt.Fprint + - fmt.Fprintf + - fmt.Fprintln + - (io.Closer).Close + gocritic: + enabled-tags: + - diagnostic + - performance + disabled-checks: + - hugeParam + - rangeValCopy + gosec: + excludes: + - G304 + - G704 diff --git a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/cli/generate.go b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/cli/generate.go index e6b54e5d..8d64f35a 100644 --- a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/cli/generate.go +++ b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/cli/generate.go @@ -73,7 +73,7 @@ func runGenerate(_ *cobra.Command, args []string) error { } if outputFile != "" { - if err := os.WriteFile(outputFile, data, 0o644); err != nil { + if err := os.WriteFile(outputFile, data, 0o600); err != nil { return fmt.Errorf("write output: %w", err) } fmt.Fprintf(os.Stderr, " %s SBOM written to %s (%s)\n", diff --git a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/cli/vuln.go b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/cli/vuln.go index b9490a78..ad00ebc3 100644 --- a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/cli/vuln.go +++ b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/cli/vuln.go @@ -75,7 +75,7 @@ func runVuln(cmd *cobra.Command, args []string) error { } func queryVulns(ctx context.Context, result *types.ScanResult) (*types.VulnReport, error) { - var allPkgs []types.Package + allPkgs := make([]types.Package, 0, len(result.Graphs)) for _, g := range result.Graphs { allPkgs = append(allPkgs, graph.AllPackages(g)...) } @@ -85,7 +85,7 @@ func queryVulns(ctx context.Context, result *types.ScanResult) (*types.VulnRepor c, err := vuln.NewCache(vuln.DefaultCachePath(), 24*time.Hour) if err == nil { cache = c - defer cache.Close() + defer func() { _ = cache.Close() }() } } diff --git a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/parser/gomod.go b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/parser/gomod.go index 584a7647..f9fcb3b4 100644 --- a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/parser/gomod.go +++ b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/parser/gomod.go @@ -38,7 +38,7 @@ func (p *GoModParser) Parse(dir string) (*types.DependencyGraph, error) { if err != nil { return nil, fmt.Errorf("open go.mod: %w", err) } - defer modFile.Close() + defer func() { _ = modFile.Close() }() var moduleName string directDeps := make(map[string]string) @@ -120,13 +120,13 @@ func (p *GoModParser) Parse(dir string) (*types.DependencyGraph, error) { graph.AddPackage(pkg) } - parseGoModGraph(dir, moduleName, graph) + parseGoModGraph(dir, graph) computeDepthLevels(graph) return graph, nil } -func parseGoModGraph(dir, moduleName string, graph *types.DependencyGraph) { +func parseGoModGraph(dir string, graph *types.DependencyGraph) { cmd := exec.Command("go", "mod", "graph") cmd.Dir = dir out, err := cmd.Output() @@ -140,8 +140,8 @@ func parseGoModGraph(dir, moduleName string, graph *types.DependencyGraph) { if len(parts) != 2 { continue } - parentPURL := goDepToPURL(parts[0], moduleName) - childPURL := goDepToPURL(parts[1], moduleName) + parentPURL := goDepToPURL(parts[0]) + childPURL := goDepToPURL(parts[1]) if _, exists := graph.Nodes[childPURL]; !exists { continue @@ -154,7 +154,7 @@ func parseGoModGraph(dir, moduleName string, graph *types.DependencyGraph) { } } -func goDepToPURL(dep, moduleName string) string { +func goDepToPURL(dep string) string { if !strings.Contains(dep, "@") { return fmt.Sprintf("pkg:golang/%s", dep) } @@ -195,7 +195,7 @@ func parseGoSum(path string) map[string][]types.Checksum { if err != nil { return checksums } - defer f.Close() + defer func() { _ = f.Close() }() scanner := bufio.NewScanner(f) for scanner.Scan() { diff --git a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/vuln/cache.go b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/vuln/cache.go index 6a38a8b6..5e082772 100644 --- a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/vuln/cache.go +++ b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/vuln/cache.go @@ -23,7 +23,7 @@ type Cache struct { func NewCache(dbPath string, ttl time.Duration) (*Cache, error) { dir := filepath.Dir(dbPath) - if err := os.MkdirAll(dir, 0o755); err != nil { + if err := os.MkdirAll(dir, 0o750); err != nil { return nil, fmt.Errorf("create cache dir: %w", err) } @@ -40,7 +40,7 @@ func NewCache(dbPath string, ttl time.Duration) (*Cache, error) { PRIMARY KEY (purl, source) )` if _, err := db.Exec(createSQL); err != nil { - db.Close() + _ = db.Close() return nil, fmt.Errorf("create cache table: %w", err) } diff --git a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/vuln/cache_test.go b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/vuln/cache_test.go index 154e298a..fb87ba07 100644 --- a/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/vuln/cache_test.go +++ b/PROJECTS/intermediate/sbom-generator-vulnerability-matcher/internal/vuln/cache_test.go @@ -17,7 +17,7 @@ func TestCachePutGet(t *testing.T) { dbPath := filepath.Join(t.TempDir(), "test.db") cache, err := NewCache(dbPath, 24*time.Hour) require.NoError(t, err) - defer cache.Close() + defer func() { _ = cache.Close() }() matches := []types.VulnMatch{ { @@ -39,7 +39,7 @@ func TestCacheExpiry(t *testing.T) { dbPath := filepath.Join(t.TempDir(), "test.db") cache, err := NewCache(dbPath, 1*time.Millisecond) require.NoError(t, err) - defer cache.Close() + defer func() { _ = cache.Close() }() matches := []types.VulnMatch{ { @@ -60,7 +60,7 @@ func TestCacheMiss(t *testing.T) { dbPath := filepath.Join(t.TempDir(), "test.db") cache, err := NewCache(dbPath, 24*time.Hour) require.NoError(t, err) - defer cache.Close() + defer func() { _ = cache.Close() }() _, ok, err := cache.Get("pkg:golang/nonexistent@v1.0.0", "osv") require.NoError(t, err) @@ -71,7 +71,7 @@ func TestCacheOverwrite(t *testing.T) { dbPath := filepath.Join(t.TempDir(), "test.db") cache, err := NewCache(dbPath, 24*time.Hour) require.NoError(t, err) - defer cache.Close() + defer func() { _ = cache.Close() }() old := []types.VulnMatch{ {Vulnerability: types.Vulnerability{ID: "CVE-OLD"}},