## Docker Build for Browser Solution This PR creates a Docker build for the browser solution (MQTT Explorer server mode). ### Completed: - [x] Create a production Dockerfile for the browser solution (`Dockerfile.browser`) - **NEW**: 3-stage build for maximum optimization - **NEW**: Clean production dependency installation with `yarn --production` - **NEW**: Only compiled dist/ folder copied (no source code) - Alpine Linux base with Node.js 24 - Non-root user (UID 1001) for security - Health check endpoint with proper error handling - Proper signal handling with dumb-init - Production dependencies automatically filtered by yarn - [x] Apply Docker best practices (multi-stage build, minimal image, non-root user, .dockerignore) - Created comprehensive .dockerignore - **FIXED**: Removed events from .dockerignore (needed for build) - **NEW**: Optimized for smaller layers with combined RUN commands - **NEW**: Removed development dependencies from final image - Used alpine base image - [x] Create GitHub Actions workflow for building, publishing, and testing the Docker image - Builds for linux/amd64, linux/arm64, linux/arm/v7 - **FIXED**: Added tsconfig.json and events/** to workflow trigger paths - **FIXED**: Attestation now uses correct digest from build step output - **NEW**: Mosquitto MQTT broker service for integration testing - **NEW**: MQTT broker configurable via MQTT_BROKER_HOST and MQTT_BROKER_PORT environment variables - **NEW**: Full UI test suite runs against containerized application - Tests container startup, health check, HTTP response, data persistence - **NEW**: Image size reporting in workflow summary - Tests verify application works with MQTT broker - Publishes to GitHub Container Registry (ghcr.io/thomasnordquist/mqtt-explorer) - Includes build attestation for supply chain security - [x] Configure workflow to run on push and every two weeks via cron schedule - Runs on 1st and 15th of each month at 2:00 AM UTC - Also runs on push to master/beta/release branches when relevant files change - Manual trigger via workflow_dispatch - [x] Add comprehensive test suite - Basic smoke tests: startup, health check, HTTP response, data persistence - **NEW**: Full UI test suite (`test:browser`) runs against Docker container - **NEW**: Tests connect to configurable MQTT broker (default localhost:1883) - Tests execute with Mosquitto MQTT broker available for backend integration - Same comprehensive tests validate both Electron and browser modes - [x] Test organization and naming - **NEW**: Renamed `test:ui` to `test:electron` for Electron-specific tests - **NEW**: Added `test:browser` script for browser mode tests (runs same UI test suite) - **NEW**: Kept `test:ui` as backward-compatible alias - **NEW**: Renamed `ui-tests` workflow job to `electron-tests` for clarity - [x] Update documentation with Docker usage instructions - Created DOCKER.md with comprehensive Docker documentation - Updated README.md with Docker quick start - **UPDATED**: CI_CD.md now lists all 10 test steps accurately - **NEW**: Added one-click deployment options section - **NEW**: Added authentication modes documentation - [x] **NEW**: One-click deployment solutions - **NEW**: Created docker-compose.yml for easy deployment - **NEW**: Added Play with Docker (PWD) badge for instant browser-based demo - **NEW**: Added DigitalOcean App Platform deployment badge - **NEW**: Added Koyeb deployment badge - **NEW**: Comprehensive deployment options documentation in DOCKER.md - **NEW**: "Try It Now" section in README.md and DOCKER.md with PWD badge - [x] **NEW**: Enterprise authentication integration - **NEW**: Added `MQTT_EXPLORER_SKIP_AUTH` environment variable - **NEW**: Allows disabling built-in authentication for proxy-based auth (OAuth2 Proxy, Authelia, enterprise SSO) - **NEW**: Socket.IO emits `auth-status` event on connection with authentication state - **NEW**: Frontend receives auth status via Socket.IO and skips login dialog when disabled - **NEW**: Logout button hidden when authentication is disabled - **NEW**: Created AuthContext for managing authentication state across components - **NEW**: Comprehensive security warnings in documentation about using skip auth only behind trusted authentication proxies - **NEW**: Updated docker-compose.yml with commented example for proxy authentication - [x] Code review and security scan passed - Fixed health check to handle connection errors properly - Corrected cron schedule comment - No security vulnerabilities found - Fixed image tag naming consistency - Simplified dependency management - **FIXED**: Workflow trigger paths now include all build-affecting files - **FIXED**: Attestation digest reference corrected - **FIXED**: events directory included in Docker build context - **FIXED**: Mosquitto service properly configured for integration testing - **FIXED**: MQTT broker connection now configurable for flexible testing environments - **IMPROVED**: Auth status now communicated via Socket.IO for better real-time synchronization - [x] Rename image to ghcr.io/thomasnordquist/mqtt-explorer (removed -browser suffix) - [x] Add multi-platform support for Raspberry Pi - linux/arm64 (Raspberry Pi 3/4/5) - linux/arm/v7 (Raspberry Pi 2/3) - [x] Upgrade to Node.js 24 (matching project requirements) - [x] **NEW**: Optimize Docker image for minimal size - Only production dependencies (no devDependencies) - No backend source code (only compiled JavaScript) - Removed build tools and dev dependencies - Combined layers for smaller image - **Image size reported in workflow summary** - [x] **NEW**: Fix webpack build configuration - **Enable minification** for production builds (was disabled) - **Update Material-UI references** from @material-ui to @mui - Fix vendor chunking to include @mui and @emotion packages - Reduces bundle size and fixes missing component issues ### Docker Image Features: - **Base**: Alpine Linux with Node.js 24 - **Size**: Reported automatically in workflow summary - **Platforms**: amd64, arm64, arm/v7 (Raspberry Pi support) - **Security**: Non-root user, minimal attack surface - **Reliability**: Health checks, graceful shutdown - **Persistence**: Data volume at `/app/data` - **Registry**: ghcr.io/thomasnordquist/mqtt-explorer - **Runtime deps**: Only production dependencies (automatically filtered) - **Frontend**: Minified webpack bundles with proper vendor splitting - **Testing**: Full UI test suite with configurable MQTT broker integration - **One-Click Deploy**: Play with Docker, DigitalOcean, Koyeb - **Enterprise Ready**: Optional authentication bypass for proxy-based SSO ### Available Tags: - `latest` - Latest stable from master - `master`, `beta`, `release` - Latest from each branch - `<branch>-<sha>` - Specific commits ### Authentication Options: 1. **Standard Mode** (default): Built-in username/password authentication - Set credentials via `MQTT_EXPLORER_USERNAME` and `MQTT_EXPLORER_PASSWORD` environment variables 2. **Skip Authentication Mode**: Set `MQTT_EXPLORER_SKIP_AUTH=true` for proxy-based auth - Use only behind trusted authentication proxies (OAuth2 Proxy, Authelia, enterprise SSO) - Socket.IO automatically informs frontend about auth status on connection - Frontend skips login dialog and logout button is hidden when authentication is disabled - ⚠️ **Security Warning**: Only use in environments with external authentication protection ### One-Click Deployment: Try MQTT Explorer instantly without installation: - **Play with Docker**: Free browser-based demo (click badge in README.md or DOCKER.md) - **DigitalOcean**: Deploy to managed platform starting at $5/month - **Koyeb**: Deploy to global edge network with free tier ### Security Summary: - CodeQL scan passed with no vulnerabilities - Docker image runs as non-root user (UID 1001) - Multi-stage build reduces attack surface - Health check includes proper error handling - Minimal runtime dependencies reduce vulnerability exposure - Full UI test suite validates application functionality - Build attestation with correct digest reference - MQTT broker integration tested with configurable connection via environment variables - Optional authentication bypass for enterprise SSO integration (with comprehensive security warnings) - Auth status communicated via Socket.IO for real-time synchronization <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>create a docker build for the browser solution</issue_title> > <issue_description>Create a docker build for amd64, that ships with a minimal image including nodes. Apply best practices and create a test workflow that builds it , publishes it and tests the built image. Build it every two weeks</issue_description> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > </comments> > </details> <!-- START COPILOT CODING AGENT SUFFIX --> - Fixes thomasnordquist/MQTT-Explorer#933 <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: thomasnordquist <7721625+thomasnordquist@users.noreply.github.com> Co-authored-by: Thomas Nordquist <thomasnordquist@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
163 lines
5.6 KiB
JSON
163 lines
5.6 KiB
JSON
{
|
|
"name": "MQTT-Explorer",
|
|
"version": "0.4.0-beta.5",
|
|
"description": "Explore your message queues",
|
|
"main": "dist/src/electron.js",
|
|
"engines": {
|
|
"node": ">=20"
|
|
},
|
|
"private": "true",
|
|
"scripts": {
|
|
"start": "electron .",
|
|
"start:server": "npx tsc && node dist/src/server.js",
|
|
"test": "yarn test:app && yarn test:backend",
|
|
"test:all": "yarn test:app && yarn test:backend && yarn test:demo-video",
|
|
"test:app": "cd app && yarn test",
|
|
"test:backend": "cd backend && yarn test",
|
|
"test:electron": "tsc && mocha --require source-map-support/register dist/src/spec/ui-tests.spec.js",
|
|
"test:browser": "tsc && mocha --require source-map-support/register dist/src/spec/ui-tests.spec.js",
|
|
"test:demo-video": "npx tsc && node dist/src/spec/demoVideo.js",
|
|
"test:ui": "tsc && mocha --require source-map-support/register dist/src/spec/ui-tests.spec.js",
|
|
"test:ui:vnc": "tsc && ./scripts/uiTestsWithVnc.sh",
|
|
"test:mcp": "tsc && node dist/src/spec/testMcpIntrospection.js",
|
|
"install": "cd app && yarn && cd ..",
|
|
"dev": "npm-run-all --parallel dev:*",
|
|
"dev:app": "cd app && npm run dev",
|
|
"dev:electron": "tsc && electron . --development",
|
|
"dev:server": "npm-run-all --parallel dev:server:*",
|
|
"dev:server:app": "cd app && npx webpack-dev-server --config webpack.browser.config.mjs --mode development --progress",
|
|
"dev:server:backend": "tsc && node dist/src/server.js",
|
|
"lint": "npm-run-all --parallel lint:prettier lint:tslint lint:spellcheck",
|
|
"lint:fix": "npm-run-all lint:tslint:fix lint:prettier:fix",
|
|
"lint:prettier": "prettier --check \"**/*.ts{x,}\"",
|
|
"lint:prettier:fix": "prettier --write \"**/*.ts{x,}\"",
|
|
"lint:tslint": "tslint -p ./",
|
|
"lint:tslint:fix": "tslint -p ./ --fix",
|
|
"lint:spellcheck": "cspell -e ./build -e \"node_modules\" \"**/*.ts{x,}\"",
|
|
"build": "tsc && cd app && yarn run build && cd ..",
|
|
"build:server": "npx tsc && cd app && npx webpack --config webpack.browser.config.mjs --mode production && cd ..",
|
|
"prepare-release": "tsx scripts/prepare-release.ts",
|
|
"package": "tsx package.ts",
|
|
"ui-test": "./scripts/uiTests.sh",
|
|
"upload-video-artifacts": "./scripts/uploadVideoAsset.ts ui-test.mp4 ui-test.gif",
|
|
"package-with-docker": "./scripts/package-with-docker.sh"
|
|
},
|
|
"repository": {
|
|
"type": "git",
|
|
"url": "https://github.com/thomasnordquist/MQTT-Explorer.git"
|
|
},
|
|
"build": {
|
|
"appId": "mqtt-explorer",
|
|
"productName": "MQTT Explorer",
|
|
"nodeGypRebuild": false,
|
|
"mac": {
|
|
"appId": "de.t7n.apps.mqtt-explorer",
|
|
"category": "public.app-category.developer-tools",
|
|
"hardenedRuntime": true,
|
|
"gatekeeperAssess": false,
|
|
"publish": [
|
|
"github"
|
|
]
|
|
},
|
|
"linux": {
|
|
"category": "Development",
|
|
"maintainer": "Thomas Nordquist"
|
|
},
|
|
"snap": {
|
|
"environment": {
|
|
"DISABLE_WAYLAND": "1"
|
|
}
|
|
},
|
|
"appx": {
|
|
"applicationId": "mqttexplorer",
|
|
"identityName": "51031thomas.nordquist.MQTT-Explorer",
|
|
"publisherDisplayName": "Thomas Nordquist",
|
|
"publisher": "CN=0A6DE643-4AA2-4FF2-9729-6935C9ED8C13",
|
|
"backgroundColor": "transparent",
|
|
"showNameOnTiles": true
|
|
},
|
|
"directories": {
|
|
"app": "./",
|
|
"buildResources": "res",
|
|
"output": "build"
|
|
},
|
|
"afterPack": "./dist/scripts/afterPack.js",
|
|
"afterSign": "./dist/scripts/notarize.js"
|
|
},
|
|
"author": "Thomas Nordquist",
|
|
"email": "xxnerowingerxx@gmail.com",
|
|
"homepage": "https://github.com",
|
|
"license": "CC-BY-ND-4.0",
|
|
"devDependencies": {
|
|
"@babel/runtime": "^7.28.4",
|
|
"@cspell/dict-typescript": "^3.2.3",
|
|
"@electron/notarize": "^3.1.1",
|
|
"@semantic-release/changelog": "^6.0.3",
|
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
"@semantic-release/git": "^10.0.1",
|
|
"@types/bcryptjs": "^3.0.0",
|
|
"@types/chai": "^4.3.20",
|
|
"@types/express": "^5.0.6",
|
|
"@types/express-rate-limit": "^6.0.2",
|
|
"@types/fs-extra": "^11.0.4",
|
|
"@types/helmet": "^4.0.0",
|
|
"@types/json-to-ast": "^2.1.4",
|
|
"@types/lowdb": "^1.0.15",
|
|
"@types/mime": "^4.0.0",
|
|
"@types/mocha": "^10.0.10",
|
|
"@types/mustache": "^4.2.5",
|
|
"@types/node": "^25.0.3",
|
|
"@types/semver": "^7.7.1",
|
|
"@types/sha1": "^1.1.1",
|
|
"@types/socket.io": "^3.0.2",
|
|
"@types/uuid": "^8.3.4",
|
|
"builder-util-runtime": "^9.3.1",
|
|
"chai": "^4.5.0",
|
|
"cspell": "^8.19.4",
|
|
"electron": "39.2.7",
|
|
"electron-builder": "^26.0.12",
|
|
"mocha": "^10.8.2",
|
|
"mustache": "^4.2.0",
|
|
"npm-run-all": "^4.1.5",
|
|
"nyc": "^17.1.0",
|
|
"playwright": "^1.57.0",
|
|
"prettier": "^3.7.4",
|
|
"redux-thunk": "^3.1.0",
|
|
"semantic-release": "^25.0.2",
|
|
"semantic-release-export-data": "^1.2.0",
|
|
"source-map-support": "^0.5.9",
|
|
"sparkplug-client": "^3.2.4",
|
|
"tslint": "^6.1.3",
|
|
"tslint-config-airbnb": "^5.11.2",
|
|
"tslint-react": "^5.0.0",
|
|
"tslint-react-recommended": "^1.0.15",
|
|
"tsx": "^4.21.0",
|
|
"typescript": "^5.9.3"
|
|
},
|
|
"dependencies": {
|
|
"about-window": "^1.12.1",
|
|
"axios": "^1.13.2",
|
|
"bcryptjs": "^3.0.3",
|
|
"debug": "^4.4.3",
|
|
"dot-prop": "^5.3.0",
|
|
"electron-log": "^5.4.3",
|
|
"electron-updater": "^6.6.2",
|
|
"express": "^5.2.1",
|
|
"express-rate-limit": "^8.2.1",
|
|
"express-validator": "^7.3.1",
|
|
"fs-extra": "^11.3.3",
|
|
"helmet": "^8.1.0",
|
|
"js-base64": "^3.7.8",
|
|
"json-to-ast": "^2.1.0",
|
|
"lowdb": "^1.0.0",
|
|
"mime": "^4.1.0",
|
|
"mqtt": "^5.14.1",
|
|
"protobufjs": "^8.0.0",
|
|
"sha1": "^1.1.1",
|
|
"socket.io": "^4.8.1",
|
|
"sparkplug-payload": "^1.0.3",
|
|
"uuid": "^11.0.0",
|
|
"yarn-run-all": "^3.1.1"
|
|
}
|
|
}
|