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:
2GT-Rich
2026-04-16 09:55:53 -07:00
parent ab9572122e
commit e43b80a9a2
10 changed files with 7727 additions and 53 deletions
+52
View File
@@ -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"
+86
View File
@@ -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
+43
View File
@@ -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
View File
@@ -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.
+17
View File
@@ -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: '^_' }],
},
}
);
+4300
View File
File diff suppressed because it is too large Load Diff
+27 -22
View File
@@ -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"
} }
} }
+33
View File
@@ -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' },
},
}
);
+3117 -30
View File
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -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"
} }
} }