Add security standards and CI infrastructure
- SECURITY.md with vulnerability disclosure policy and self-hosting guidance - Dependabot config for weekly dependency updates (npm, Docker, Actions) - ESLint v9 flat config for frontend and backend, with eslint-plugin-security - GitHub Actions CI: lint, typecheck, build, and npm audit on every push/PR - CodeQL workflow for automated security scanning (runs on push and weekly)
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
# Frontend npm dependencies
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/frontend"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
open-pull-requests-limit: 5
|
||||||
|
labels:
|
||||||
|
- "dependencies"
|
||||||
|
- "frontend"
|
||||||
|
|
||||||
|
# Backend npm dependencies
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/backend"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
open-pull-requests-limit: 5
|
||||||
|
labels:
|
||||||
|
- "dependencies"
|
||||||
|
- "backend"
|
||||||
|
|
||||||
|
# Docker dependencies (docker-compose.yml base images)
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "/backend"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
labels:
|
||||||
|
- "dependencies"
|
||||||
|
- "docker"
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "/nginx"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
labels:
|
||||||
|
- "dependencies"
|
||||||
|
- "docker"
|
||||||
|
|
||||||
|
# GitHub Actions workflow dependencies
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
labels:
|
||||||
|
- "dependencies"
|
||||||
|
- "github-actions"
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
frontend:
|
||||||
|
name: Frontend — Lint, Type-check & Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: frontend
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: frontend/package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Type-check
|
||||||
|
run: npx tsc --noEmit
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
backend:
|
||||||
|
name: Backend — Lint, Type-check & Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: backend
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: backend/package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Type-check
|
||||||
|
run: npx tsc --noEmit
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
audit:
|
||||||
|
name: Security Audit
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Audit frontend dependencies
|
||||||
|
run: npm audit --audit-level=high
|
||||||
|
working-directory: frontend
|
||||||
|
|
||||||
|
- name: Audit backend dependencies
|
||||||
|
run: npm audit --audit-level=high
|
||||||
|
working-directory: backend
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
name: CodeQL Security Analysis
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
schedule:
|
||||||
|
# Run every Monday at 08:00 UTC
|
||||||
|
- cron: '0 8 * * 1'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze (${{ matrix.language }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [javascript-typescript]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v3
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# CodeQL queries to run — security-extended adds more security checks
|
||||||
|
queries: security-extended
|
||||||
|
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v3
|
||||||
|
with:
|
||||||
|
category: "/language:${{ matrix.language }}"
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | --------- |
|
||||||
|
| 0.10.x (current beta) | Yes |
|
||||||
|
| Earlier versions | No |
|
||||||
|
|
||||||
|
MikroTik Manager is currently in beta. Security fixes will be applied to the latest release only.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||||
|
|
||||||
|
If you discover a security vulnerability, please use one of the following channels:
|
||||||
|
|
||||||
|
- **GitHub Private Security Advisory** *(preferred)*: Use the [Report a Vulnerability](../../security/advisories/new) button in the Security tab of this repository. This lets us discuss the issue privately before public disclosure.
|
||||||
|
- **Email**: Send details to the repository maintainer via the contact information on their GitHub profile.
|
||||||
|
|
||||||
|
### What to include in your report
|
||||||
|
|
||||||
|
- A description of the vulnerability and its potential impact
|
||||||
|
- Steps to reproduce the issue
|
||||||
|
- Any proof-of-concept code (if applicable)
|
||||||
|
- Your suggested fix (if you have one)
|
||||||
|
|
||||||
|
### What to expect
|
||||||
|
|
||||||
|
- **Acknowledgement** within 3 business days
|
||||||
|
- **Status update** within 7 days (confirmed, need more info, or not a vulnerability)
|
||||||
|
- **Fix and disclosure** coordinated with you once a patch is ready
|
||||||
|
|
||||||
|
We ask that you give us reasonable time to address the issue before any public disclosure. We will credit you in the release notes if you wish.
|
||||||
|
|
||||||
|
## Security Considerations for Self-Hosted Deployments
|
||||||
|
|
||||||
|
MikroTik Manager is designed to be run on your local network. A few things to keep in mind:
|
||||||
|
|
||||||
|
- **Do not expose this application directly to the public internet.** It is intended for LAN or VPN-only access.
|
||||||
|
- The `.env` file contains sensitive credentials (JWT secret, encryption key, database passwords). Protect this file and never commit it to version control.
|
||||||
|
- Device credentials stored in the database are encrypted at rest using AES-256.
|
||||||
|
- HTTPS is enforced by default. The included nginx configuration redirects all HTTP traffic to HTTPS.
|
||||||
|
- Default credentials should be changed immediately after first login.
|
||||||
|
- The built-in role-based access control (Admin / Operator / Viewer) should be used to limit user privileges.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import js from '@eslint/js';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
import security from 'eslint-plugin-security';
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{ ignores: ['dist/**', 'node_modules/**'] },
|
||||||
|
js.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
security.configs.recommended,
|
||||||
|
{
|
||||||
|
files: ['src/**/*.ts'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-explicit-any': 'warn',
|
||||||
|
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
Generated
+4300
File diff suppressed because it is too large
Load Diff
+27
-22
@@ -7,40 +7,45 @@
|
|||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/index.js",
|
||||||
"dev": "nodemon --watch src --ext ts --exec ts-node src/index.ts",
|
"dev": "nodemon --watch src --ext ts --exec ts-node src/index.ts",
|
||||||
|
"lint": "eslint src",
|
||||||
"migrate": "ts-node src/db/migrate.ts"
|
"migrate": "ts-node src/db/migrate.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.2",
|
|
||||||
"cors": "^2.8.5",
|
|
||||||
"helmet": "^7.1.0",
|
|
||||||
"compression": "^1.7.4",
|
|
||||||
"express-async-errors": "^3.1.1",
|
|
||||||
"jsonwebtoken": "^9.0.2",
|
|
||||||
"bcryptjs": "^2.4.3",
|
|
||||||
"pg": "^8.11.3",
|
|
||||||
"@influxdata/influxdb-client": "^1.33.2",
|
"@influxdata/influxdb-client": "^1.33.2",
|
||||||
"ioredis": "^5.3.2",
|
"bcryptjs": "^2.4.3",
|
||||||
"bullmq": "^5.1.1",
|
"bullmq": "^5.1.1",
|
||||||
|
"compression": "^1.7.4",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"express-async-errors": "^3.1.1",
|
||||||
|
"helmet": "^7.1.0",
|
||||||
|
"ioredis": "^5.3.2",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"morgan": "^1.10.0",
|
||||||
|
"nodemailer": "^6.9.13",
|
||||||
|
"pg": "^8.11.3",
|
||||||
"socket.io": "^4.6.1",
|
"socket.io": "^4.6.1",
|
||||||
"ssh2": "^1.14.0",
|
"ssh2": "^1.14.0",
|
||||||
"zod": "^3.22.4",
|
"zod": "^3.22.4"
|
||||||
"dotenv": "^16.3.1",
|
|
||||||
"morgan": "^1.10.0",
|
|
||||||
"nodemailer": "^6.9.13"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.21",
|
"@eslint/js": "^9.39.4",
|
||||||
"@types/cors": "^2.8.17",
|
|
||||||
"@types/compression": "^1.7.5",
|
|
||||||
"@types/jsonwebtoken": "^9.0.5",
|
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
"@types/pg": "^8.10.9",
|
"@types/compression": "^1.7.5",
|
||||||
"@types/ssh2": "^1.11.17",
|
"@types/cors": "^2.8.17",
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
|
"@types/jsonwebtoken": "^9.0.5",
|
||||||
"@types/morgan": "^1.9.9",
|
"@types/morgan": "^1.9.9",
|
||||||
"@types/node": "^20.10.5",
|
"@types/node": "^20.10.5",
|
||||||
"typescript": "^5.3.3",
|
"@types/nodemailer": "^6.4.14",
|
||||||
"ts-node": "^10.9.2",
|
"@types/pg": "^8.10.9",
|
||||||
|
"@types/ssh2": "^1.11.17",
|
||||||
|
"eslint": "^9.39.4",
|
||||||
|
"eslint-plugin-security": "^4.0.0",
|
||||||
"nodemon": "^3.0.2",
|
"nodemon": "^3.0.2",
|
||||||
"@types/nodemailer": "^6.4.14"
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.3.3",
|
||||||
|
"typescript-eslint": "^8.58.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import js from '@eslint/js';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
import reactPlugin from 'eslint-plugin-react';
|
||||||
|
import reactHooks from 'eslint-plugin-react-hooks';
|
||||||
|
import security from 'eslint-plugin-security';
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{ ignores: ['dist/**', 'node_modules/**'] },
|
||||||
|
js.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
security.configs.recommended,
|
||||||
|
{
|
||||||
|
files: ['src/**/*.{ts,tsx}'],
|
||||||
|
plugins: {
|
||||||
|
react: reactPlugin,
|
||||||
|
'react-hooks': reactHooks,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// React rules
|
||||||
|
...reactPlugin.configs.recommended.rules,
|
||||||
|
...reactHooks.configs.recommended.rules,
|
||||||
|
'react/react-in-jsx-scope': 'off', // Not needed with React 17+ JSX transform
|
||||||
|
'react/prop-types': 'off', // TypeScript handles this
|
||||||
|
|
||||||
|
// TypeScript rules
|
||||||
|
'@typescript-eslint/no-explicit-any': 'warn',
|
||||||
|
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
react: { version: 'detect' },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
Generated
+3117
-30
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
|||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "eslint src --ext .ts,.tsx"
|
"lint": "eslint src"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/react-query": "^5.17.1",
|
"@tanstack/react-query": "^5.17.1",
|
||||||
@@ -29,13 +29,19 @@
|
|||||||
"zustand": "^4.4.7"
|
"zustand": "^4.4.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.39.4",
|
||||||
"@types/react": "^18.2.48",
|
"@types/react": "^18.2.48",
|
||||||
"@types/react-dom": "^18.2.18",
|
"@types/react-dom": "^18.2.18",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.17",
|
||||||
|
"eslint": "^9.39.4",
|
||||||
|
"eslint-plugin-react": "^7.37.5",
|
||||||
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
|
"eslint-plugin-security": "^4.0.0",
|
||||||
"postcss": "^8.4.33",
|
"postcss": "^8.4.33",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
|
"typescript-eslint": "^8.58.2",
|
||||||
"vite": "^5.0.11"
|
"vite": "^5.0.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user