diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..54f3f71 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,46 @@ +# Git +.git +.gitignore + +# Build artifacts +target/ +dist/ +build/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# Documentation +docs/ + +# Development files +*.md +!README.md +Makefile + +# Test files +tests/ +*_test.rs +*.test.ts +*.spec.ts + +# CI/CD +.github/ + +# Local configuration +config/ +!config/galvanize.example.toml +!config/users.example.toml +.env +.env.* + +# Node modules (handled separately in webui build) +webui/node_modules/ + +# OS files +.DS_Store +Thumbs.db + diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..a5ed580 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,49 @@ +--- +name: Bug Report +about: Create a report to help us improve +title: "[BUG] " +labels: bug +assignees: '' +--- + +## Describe the Bug + +A clear and concise description of what the bug is. + +## To Reproduce + +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '...' +3. See error + +## Expected Behavior + +A clear and concise description of what you expected to happen. + +## Actual Behavior + +What actually happened. + +## Screenshots + +If applicable, add screenshots to help explain your problem. + +## Environment + +- **OS**: [e.g., Ubuntu 22.04, macOS 14, Windows 11] +- **Galvanize Version**: [e.g., 0.1.0] +- **Rust Version**: [e.g., 1.75.0] +- **Installation Method**: [e.g., binary, Docker, source] + +## Logs + +``` +Paste relevant log output here +``` + +## Additional Context + +Add any other context about the problem here. + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..3536150 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,29 @@ +--- +name: Feature Request +about: Suggest an idea for this project +title: "[FEATURE] " +labels: enhancement +assignees: '' +--- + +## Is your feature request related to a problem? + +A clear and concise description of what the problem is. +Ex. I'm always frustrated when [...] + +## Describe the solution you'd like + +A clear and concise description of what you want to happen. + +## Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. + +## Use Case + +Describe the use case for this feature. How would it be used? + +## Additional Context + +Add any other context or screenshots about the feature request here. + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f1a0d45 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,33 @@ +## Description + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. + +Fixes # (issue) + +## Type of Change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update + +## How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. + +- [ ] Test A +- [ ] Test B + +## Checklist + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published in downstream modules + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8a9436b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,112 @@ +name: CI + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + +jobs: + # ========================================================================== + # Rust Checks + # ========================================================================== + rust-check: + name: Rust Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-action@stable + with: + components: rustfmt, clippy + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Run clippy + run: cargo clippy --all-targets --all-features -- -D warnings + + - name: Run tests + run: cargo test --all-features --verbose + + # ========================================================================== + # Web UI Checks + # ========================================================================== + webui-check: + name: Web UI Check + runs-on: ubuntu-latest + defaults: + run: + working-directory: webui + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Cache pnpm dependencies + uses: actions/cache@v4 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-${{ hashFiles('webui/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm lint + + - name: Type check + run: pnpm typecheck + + - name: Build + run: pnpm build + + # ========================================================================== + # Security Audit + # ========================================================================== + security-audit: + name: Security Audit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-action@stable + + - name: Install cargo-audit + run: cargo install cargo-audit + + - name: Run security audit + run: cargo audit + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6b71f9e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,209 @@ +name: Release + +on: + push: + tags: + - "v*" + +env: + CARGO_TERM_COLOR: always + +permissions: + contents: write + packages: write + +jobs: + # ========================================================================== + # Build Web UI + # ========================================================================== + build-webui: + name: Build Web UI + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Install dependencies + working-directory: webui + run: pnpm install --frozen-lockfile + + - name: Build + working-directory: webui + run: pnpm build + + - name: Upload Web UI artifacts + uses: actions/upload-artifact@v4 + with: + name: webui-dist + path: webui/dist + + # ========================================================================== + # Build Binaries + # ========================================================================== + build-binaries: + name: Build (${{ matrix.target }}) + needs: build-webui + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + name: galvanize-linux-x86_64 + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + name: galvanize-linux-aarch64 + - target: x86_64-apple-darwin + os: macos-latest + name: galvanize-darwin-x86_64 + - target: aarch64-apple-darwin + os: macos-latest + name: galvanize-darwin-aarch64 + - target: x86_64-pc-windows-msvc + os: windows-latest + name: galvanize-windows-x86_64.exe + + steps: + - uses: actions/checkout@v4 + + - name: Download Web UI artifacts + uses: actions/download-artifact@v4 + with: + name: webui-dist + path: webui/dist + + - name: Install Rust toolchain + uses: dtolnay/rust-action@stable + with: + targets: ${{ matrix.target }} + + - name: Install cross-compilation tools + if: matrix.target == 'aarch64-unknown-linux-gnu' + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + + - name: Build binary + run: cargo build --release --target ${{ matrix.target }} --features webui + env: + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc + + - name: Prepare binary (Unix) + if: runner.os != 'Windows' + run: | + cp target/${{ matrix.target }}/release/galvanize ${{ matrix.name }} + chmod +x ${{ matrix.name }} + + - name: Prepare binary (Windows) + if: runner.os == 'Windows' + run: cp target/${{ matrix.target }}/release/galvanize.exe ${{ matrix.name }} + + - name: Upload binary + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.name }} + path: ${{ matrix.name }} + + # ========================================================================== + # Build Docker Image + # ========================================================================== + build-docker: + name: Build Docker Image + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: | + aitiome/galvanize:latest + aitiome/galvanize:${{ steps.version.outputs.VERSION }} + ghcr.io/aitiome/galvanize:latest + ghcr.io/aitiome/galvanize:${{ steps.version.outputs.VERSION }} + cache-from: type=gha + cache-to: type=gha,mode=max + + # ========================================================================== + # Create GitHub Release + # ========================================================================== + create-release: + name: Create Release + needs: [build-binaries, build-docker] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Create checksums + run: | + cd artifacts + for dir in galvanize-*; do + if [ -d "$dir" ]; then + cd "$dir" + sha256sum * > ../checksums-$dir.txt + cd .. + fi + done + cat checksums-*.txt > SHA256SUMS.txt + rm checksums-*.txt + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + name: Galvanize v${{ steps.version.outputs.VERSION }} + draft: false + prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }} + generate_release_notes: true + files: | + artifacts/galvanize-linux-x86_64/* + artifacts/galvanize-linux-aarch64/* + artifacts/galvanize-darwin-x86_64/* + artifacts/galvanize-darwin-aarch64/* + artifacts/galvanize-windows-x86_64.exe/* + artifacts/SHA256SUMS.txt + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae680bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,89 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +# Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds +*.exp +*.lib +*.pdb + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Environment +.env +.env.local +.env.*.local + +# macOS +.DS_Store +.AppleDouble +.LSOverride +._* + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini + +# Linux +*~ + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Runtime data +pids/ +*.pid +*.seed +*.pid.lock + +# Coverage +coverage/ +*.lcov +tarpaulin-report.html +tarpaulin-report.json + +# Web UI +webui/node_modules/ +webui/dist/ +webui/.turbo/ + +# Build artifacts +dist/ +build/ + +# Config (local development) +config/ +!config/galvanize.example.toml +!config/devices/.gitkeep + +# Temporary files +tmp/ +temp/ +*.tmp + +# Documentation build +docs/book/ + +# Test artifacts +test-results/ +playwright-report/ + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..df03f3d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,60 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- Initial project setup +- HTTP REST API for Wake-on-LAN operations +- MQTT support for device wake commands +- Basic username/password authentication +- OIDC provider integration +- JSON-based device configuration persistence +- Configuration file hot-reload with file system watching +- React + shadcn/ui Web UI dashboard +- Docker image and docker-compose setup +- Multi-platform binary releases (Linux, macOS, Windows) + +### Changed + +- N/A + +### Deprecated + +- N/A + +### Removed + +- N/A + +### Fixed + +- N/A + +### Security + +- N/A + +## [0.1.0] - YYYY-MM-DD + +### Added + +- Initial release of Galvanize +- Core Wake-on-LAN functionality +- HTTP API with RESTful endpoints +- MQTT protocol support +- Basic and OIDC authentication +- Web UI for device management +- Configuration persistence and hot-reload +- Docker support with multi-arch images + +--- + +[Unreleased]: https://github.com/aitiome/galvanize/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/aitiome/galvanize/releases/tag/v0.1.0 + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..005c1ec --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,252 @@ +# Contributing to Galvanize + +First off, thank you for considering contributing to Galvanize! It's people like you that make Galvanize such a great tool. + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [Getting Started](#getting-started) +- [Development Setup](#development-setup) +- [How to Contribute](#how-to-contribute) +- [Pull Request Process](#pull-request-process) +- [Coding Standards](#coding-standards) +- [Commit Messages](#commit-messages) + +## Code of Conduct + +This project and everyone participating in it is governed by our commitment to providing a welcoming and inclusive environment. By participating, you are expected to uphold this commitment. Please report unacceptable behavior to [contact@aitiome.org](mailto:contact@aitiome.org). + +### Our Standards + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +## Getting Started + +### Prerequisites + +- **Rust 1.75+** - Install via [rustup](https://rustup.rs/) +- **Node.js 20+** - For Web UI development +- **pnpm** - Package manager for Web UI +- **Docker** (optional) - For container builds + +### Development Setup + +1. **Clone the repository:** + +```bash +git clone https://github.com/aitiome/galvanize.git +cd galvanize +``` + +2. **Setup Rust environment:** + +```bash +# Install Rust (if not already installed) +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + +# Install additional components +rustup component add rustfmt clippy +``` + +3. **Setup Web UI environment:** + +```bash +cd webui +pnpm install +``` + +4. **Build the project:** + +```bash +# Build server only +cargo build + +# Build with Web UI +cargo build --features webui +``` + +5. **Run tests:** + +```bash +# Rust tests +cargo test + +# Web UI tests +cd webui && pnpm test +``` + +## How to Contribute + +### Reporting Bugs + +Before creating bug reports, please check existing issues to avoid duplicates. + +When creating a bug report, please include: + +- **Clear title** describing the issue +- **Steps to reproduce** the behavior +- **Expected behavior** - what you expected to happen +- **Actual behavior** - what actually happened +- **Environment details:** + - OS and version + - Rust version (`rustc --version`) + - Galvanize version +- **Screenshots** (if applicable) +- **Logs** (if applicable) + +### Suggesting Features + +Feature requests are welcome! Please provide: + +- **Clear title** describing the feature +- **Detailed description** of the proposed functionality +- **Use case** - why is this feature needed? +- **Possible implementation** (optional) + +### Your First Code Contribution + +Looking for something to work on? Check out issues labeled: + +- `good first issue` - Good for newcomers +- `help wanted` - Extra attention needed +- `documentation` - Documentation improvements + +## Pull Request Process + +1. **Fork the repository** and create your branch from `main`: + +```bash +git checkout -b feature/my-new-feature +# or +git checkout -b fix/bug-description +``` + +2. **Make your changes** following our coding standards. + +3. **Write tests** for your changes. + +4. **Ensure all tests pass:** + +```bash +cargo test +cargo clippy -- -D warnings +cargo fmt -- --check +``` + +5. **Update documentation** if needed. + +6. **Commit your changes** using conventional commit messages. + +7. **Push to your fork** and submit a Pull Request. + +8. **Describe your changes** in the PR description: + - What does this PR do? + - How has it been tested? + - Are there any breaking changes? + +### PR Review Process + +- PRs require at least one approving review +- CI checks must pass +- PRs should be up to date with `main` before merging + +## Coding Standards + +### Rust + +- Follow the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/) +- Use `rustfmt` for formatting +- Address all `clippy` warnings +- Write documentation for public APIs +- Include unit tests for new functionality + +```rust +// Good: Documented public function with error handling +/// Sends a Wake-on-LAN magic packet to the specified MAC address. +/// +/// # Arguments +/// +/// * `mac` - The MAC address of the target device +/// * `broadcast` - Optional broadcast address (defaults to 255.255.255.255) +/// +/// # Errors +/// +/// Returns an error if the magic packet cannot be sent. +pub fn wake_device(mac: &MacAddress, broadcast: Option) -> Result<(), WolError> { + // Implementation +} +``` + +### TypeScript/React (Web UI) + +- Use TypeScript strict mode +- Follow ESLint and Prettier configuration +- Use functional components with hooks +- Keep components small and focused + +```typescript +// Good: Typed component with proper props interface +interface DeviceCardProps { + device: Device; + onWake: (id: string) => Promise; +} + +export function DeviceCard({ device, onWake }: DeviceCardProps) { + // Implementation +} +``` + +## Commit Messages + +We use [Conventional Commits](https://www.conventionalcommits.org/) format: + +``` +(): + + + +