diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 8481731..993f2a6 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -2,10 +2,7 @@ name: Build .deb Package on: push: - branches: [master] tags: ["v*"] - pull_request: - branches: [master] env: CARGO_TERM_COLOR: always diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..a92a9ec --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,180 @@ +name: CI Quality Gates + +on: + push: + branches: [master] + pull_request: + branches: [master] + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + +jobs: + rust-format: + name: Rust Format Check + runs-on: linux + steps: + - name: Checkout repository + run: | + TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" + curl -sf -H "Authorization: token ${TOKEN}" \ + "http://192.168.2.189:3000/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" \ + -o repo.tar.gz + tar xzf repo.tar.gz --strip-components=1 + rm repo.tar.gz + + - name: Ensure Rust toolchain + run: | + . "$HOME/.cargo/env" 2>/dev/null || true + if ! command -v cargo &>/dev/null; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + . "$HOME/.cargo/env" + fi + rustup component add rustfmt + echo "Rust: $(cargo --version)" + echo "Rustfmt: $(rustfmt --version)" + + - name: Check formatting + run: | + . "$HOME/.cargo/env" + cargo fmt --check --all 2>&1 + echo "All Rust code is properly formatted" + + clippy: + name: Clippy Lints + runs-on: linux + steps: + - name: Checkout repository + run: | + TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" + curl -sf -H "Authorization: token ${TOKEN}" \ + "http://192.168.2.189:3000/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" \ + -o repo.tar.gz + tar xzf repo.tar.gz --strip-components=1 + rm repo.tar.gz + + - name: Install system dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends pkg-config libssl-dev + + - name: Ensure Rust toolchain + run: | + . "$HOME/.cargo/env" 2>/dev/null || true + if ! command -v cargo &>/dev/null; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + . "$HOME/.cargo/env" + fi + rustup component add clippy + echo "Rust: $(cargo --version)" + echo "Clippy: $(cargo clippy --version)" + + - name: Run Clippy + run: | + . "$HOME/.cargo/env" + cargo clippy --all-targets --all-features -- \ + -D warnings \ + -D clippy::all \ + -D clippy::pedantic \ + -A clippy::module-name-repetitions \ + -A clippy::too-many-arguments \ + -A clippy::cast-possible-truncation \ + -A clippy::cast-possible-wrap \ + -A clippy::missing-errors-doc \ + -A clippy::missing-panics-doc 2>&1 + echo "No Clippy warnings" + + rust-test: + name: Rust Unit Tests + runs-on: linux + steps: + - name: Checkout repository + run: | + TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" + curl -sf -H "Authorization: token ${TOKEN}" \ + "http://192.168.2.189:3000/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" \ + -o repo.tar.gz + tar xzf repo.tar.gz --strip-components=1 + rm repo.tar.gz + + - name: Install system dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends pkg-config libssl-dev + + - name: Ensure Rust toolchain + run: | + . "$HOME/.cargo/env" 2>/dev/null || true + if ! command -v cargo &>/dev/null; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + . "$HOME/.cargo/env" + fi + echo "Rust: $(cargo --version)" + + - name: Run tests + run: | + . "$HOME/.cargo/env" + cargo test --workspace --all-features 2>&1 + echo "All Rust tests passed" + + security-audit: + name: Security Audit + runs-on: linux + steps: + - name: Checkout repository + run: | + TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" + curl -sf -H "Authorization: token ${TOKEN}" \ + "http://192.168.2.189:3000/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" \ + -o repo.tar.gz + tar xzf repo.tar.gz --strip-components=1 + rm repo.tar.gz + + - name: Ensure Rust toolchain + run: | + . "$HOME/.cargo/env" 2>/dev/null || true + if ! command -v cargo &>/dev/null; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + . "$HOME/.cargo/env" + fi + + - name: Install cargo-audit + run: | + . "$HOME/.cargo/env" + cargo install cargo-audit 2>/dev/null || true + + - name: Run security audit + run: | + . "$HOME/.cargo/env" + cargo audit 2>&1 + echo "No known security vulnerabilities" + + frontend-lint: + name: Frontend Lint & Type Check + runs-on: linux + steps: + - name: Checkout repository + run: | + TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" + curl -sf -H "Authorization: token ${TOKEN}" \ + "http://192.168.2.189:3000/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" \ + -o repo.tar.gz + tar xzf repo.tar.gz --strip-components=1 + rm repo.tar.gz + + - name: Install Node.js dependencies + working-directory: frontend + run: npm ci + + - name: Run ESLint + working-directory: frontend + run: | + npx eslint src/ --ext .ts,.tsx --max-warnings 0 2>&1 + echo "No ESLint errors" + + - name: TypeScript type check + working-directory: frontend + run: | + npx tsc --noEmit 2>&1 + echo "TypeScript types are valid" diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..9fce9b1 --- /dev/null +++ b/clippy.toml @@ -0,0 +1,11 @@ +# Linux Patch Manager - Clippy Lint Configuration +# Run: cargo clippy -- -D warnings (CI) or cargo clippy (local) + +# Deny all warnings in CI - warnings become errors +cognitive-complexity-threshold = 30 + +# Type complexity limits +type-complexity-threshold = 300 + +# Single character binding names allowed for common patterns (i, j, k, e, f, etc.) +allow-single-char-binding-names = ["i", "j", "k", "n", "e", "f", "r", "w", "x", "y", "z"] diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 0000000..dbcb52c --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,59 @@ +import js from '@eslint/js'; +import tseslint from '@typescript-eslint/eslint-plugin'; +import tsparser from '@typescript-eslint/parser'; + +export default [ + { + files: ['src/**/*.{ts,tsx}'], + languageOptions: { + parser: tsparser, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + ecmaFeatures: { jsx: true }, + project: './tsconfig.json', + }, + }, + plugins: { + '@typescript-eslint': tseslint, + }, + rules: { + // Error rules + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-non-null-assertion': 'warn', + '@typescript-eslint/no-empty-interface': 'warn', + '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }], + + // Security rules + 'no-eval': 'error', + 'no-implied-eval': 'error', + 'no-new-func': 'error', + 'no-unsafe-optional-chaining': 'error', + + // Code quality + 'no-console': ['warn', { allow: ['warn', 'error'] }], + 'no-debugger': 'error', + 'no-duplicate-imports': 'error', + 'no-unreachable': 'error', + 'no-constant-condition': 'warn', + 'prefer-const': 'error', + 'no-var': 'error', + 'eqeqeq': ['error', 'always'], + 'curly': ['error', 'multi-line'], + + // React-specific + 'react/jsx-no-duplicate-props': 'error', + 'react/jsx-no-undef': 'error', + 'react/no-direct-mutation-state': 'error', + 'react/no-unused-state': 'warn', + }, + }, + { + files: ['**/*.js'], + rules: { + '@typescript-eslint/no-var-requires': 'off', + }, + }, +]; diff --git a/frontend/package.json b/frontend/package.json index 1ee43dd..943b80a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,7 +7,7 @@ "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint": "eslint src/ --ext .ts,.tsx --max-warnings 0", "type-check": "tsc --noEmit" }, "dependencies": { diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..977d0bc --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,24 @@ +# Linux Patch Manager - Rust Formatting Configuration +# Run: cargo fmt --check (CI) or cargo fmt (fix) + +edition = "2021" +max_width = 100 +hard_tabs = false +tab_spaces = 4 +newline_style = "Unix" +use_small_heuristics = "Default" +reorder_imports = true +reorder_modules = true +remove_nested_parens = true +fn_single_line = false +where_single_line = false +imports_granularity = "Crate" +group_imports = "StdExternalCrate" +normalize_doc_attributes = true +wrap_comments = true +comment_width = 80 +indent_style = "Block" +trailing_comma = "Vertical" +match_block_trailing_comma = true +blank_lines_lower_bound = 0 +blank_lines_upper_bound = 1