mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-18 01:34:00 -05:00
Merge branch 'main' of git@github.com:blackboxprogramming/BlackRoad-Operating-System.git
This commit is contained in:
19
.github/CODEOWNERS
vendored
19
.github/CODEOWNERS
vendored
@@ -1,8 +1,13 @@
|
|||||||
# Canonical code ownership for BlackRoad OS meta repository
|
# BlackRoad OS Code Owners
|
||||||
# Keep ownership broad and predictable; satellite repos may define finer rules.
|
* @alexa
|
||||||
|
|
||||||
* @alexa-amundson
|
# Python services
|
||||||
/docs/ @docs-team @alexa-amundson
|
*.py @alexa
|
||||||
/os-spec/ @infra-team @alexa-amundson
|
|
||||||
/tools/ @infra-team @alexa-amundson
|
# Railway configurations
|
||||||
/.github/ @infra-team @alexa-amundson
|
railway*.json @alexa
|
||||||
|
railway*.toml @alexa
|
||||||
|
|
||||||
|
# Security-sensitive files
|
||||||
|
.env* @alexa
|
||||||
|
*secret* @alexa
|
||||||
|
|||||||
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,14 +1,24 @@
|
|||||||
# Summary
|
# Pull Request
|
||||||
<!-- High-level explanation of the change and the services it touches -->
|
|
||||||
|
|
||||||
## Checklist
|
## Description
|
||||||
- [ ] Linked the relevant issue or task
|
|
||||||
- [ ] Updated docs or specs if behavior changed
|
## Type of Change
|
||||||
- [ ] Added or adjusted tests (or noted why not needed)
|
- [ ] Bug fix
|
||||||
- [ ] Ran required checks locally (lint/test/build)
|
- [ ] New feature
|
||||||
|
- [ ] Breaking change
|
||||||
|
- [ ] Documentation update
|
||||||
|
- [ ] Infrastructure/DevOps change
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
<!-- List commands run locally, e.g. npm test -->
|
- [ ] Tested locally
|
||||||
|
- [ ] Health checks pass
|
||||||
|
- [ ] Railway deployment succeeds
|
||||||
|
|
||||||
## Notes
|
## Checklist
|
||||||
<!-- Deployment impacts, follow-ups, or escalations -->
|
- [ ] Code follows project style
|
||||||
|
- [ ] Self-reviewed code
|
||||||
|
- [ ] Updated documentation
|
||||||
|
- [ ] Tests pass
|
||||||
|
|
||||||
|
---
|
||||||
|
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||||
|
|||||||
103
.github/workflows/auto-assign.yml
vendored
Normal file
103
.github/workflows/auto-assign.yml
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Auto-Assign Reviewers
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Automatically assigns reviewers to pull requests based on files changed.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Auto Assign
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, ready_for_review]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
auto-assign:
|
||||||
|
name: Auto Assign Reviewers
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed
|
||||||
|
uses: tj-actions/changed-files@v41
|
||||||
|
with:
|
||||||
|
files_yaml: |
|
||||||
|
quantum:
|
||||||
|
- 'blackroad-quantum*.py'
|
||||||
|
- 'quantum-ml/**'
|
||||||
|
operator:
|
||||||
|
- 'operator_http.py'
|
||||||
|
- 'ledger_*.py'
|
||||||
|
- 'promotion_engine.py'
|
||||||
|
agents:
|
||||||
|
- 'agents/**'
|
||||||
|
- 'agent-*.sh'
|
||||||
|
infrastructure:
|
||||||
|
- 'blackroad-docker.sh'
|
||||||
|
- 'blackroad-k8s.sh'
|
||||||
|
- 'blackroad-railway.sh'
|
||||||
|
- 'pi-setup/**'
|
||||||
|
docs:
|
||||||
|
- '**/*.md'
|
||||||
|
- 'docs/**'
|
||||||
|
ci:
|
||||||
|
- '.github/**'
|
||||||
|
|
||||||
|
- name: Add labels based on changed files
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const labels = [];
|
||||||
|
|
||||||
|
if ('${{ steps.changed.outputs.quantum_any_changed }}' === 'true') {
|
||||||
|
labels.push('quantum');
|
||||||
|
}
|
||||||
|
if ('${{ steps.changed.outputs.operator_any_changed }}' === 'true') {
|
||||||
|
labels.push('operator');
|
||||||
|
}
|
||||||
|
if ('${{ steps.changed.outputs.agents_any_changed }}' === 'true') {
|
||||||
|
labels.push('agents');
|
||||||
|
}
|
||||||
|
if ('${{ steps.changed.outputs.infrastructure_any_changed }}' === 'true') {
|
||||||
|
labels.push('infrastructure');
|
||||||
|
}
|
||||||
|
if ('${{ steps.changed.outputs.docs_any_changed }}' === 'true') {
|
||||||
|
labels.push('documentation');
|
||||||
|
}
|
||||||
|
if ('${{ steps.changed.outputs.ci_any_changed }}' === 'true') {
|
||||||
|
labels.push('ci');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labels.length > 0) {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
labels: labels
|
||||||
|
});
|
||||||
|
console.log(`Added labels: ${labels.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Auto-assign author
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const pr = context.payload.pull_request;
|
||||||
|
|
||||||
|
// Assign the PR author
|
||||||
|
await github.rest.issues.addAssignees({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: pr.number,
|
||||||
|
assignees: [pr.user.login]
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Assigned ${pr.user.login} to PR #${pr.number}`);
|
||||||
158
.github/workflows/ci.yml
vendored
158
.github/workflows/ci.yml
vendored
@@ -1,26 +1,156 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - CI Pipeline
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Continuous Integration workflow for BlackRoad OS components.
|
||||||
|
# Runs on push to main/master and all pull requests.
|
||||||
|
#
|
||||||
|
# Jobs:
|
||||||
|
# - lint: Shell and Python linting
|
||||||
|
# - test-python: Python syntax validation and unit tests
|
||||||
|
# - test-shell: ShellCheck validation
|
||||||
|
# - security: Basic security scanning
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main, master, staging, develop]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
branches: [main, master, staging, develop]
|
||||||
|
|
||||||
permissions:
|
env:
|
||||||
contents: read
|
PYTHON_VERSION: "3.11"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-test:
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Lint Job - Check code style and syntax
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
lint:
|
||||||
|
name: Lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Checkout code
|
||||||
- name: Use Node.js
|
uses: actions/checkout@v4
|
||||||
uses: actions/setup-node@v4
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
cache: 'npm'
|
|
||||||
|
- name: Install linters
|
||||||
|
run: |
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install ruff black
|
||||||
|
|
||||||
|
- name: Run Ruff (Python linter)
|
||||||
|
run: ruff check --output-format=github . || true
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Check Python formatting with Black
|
||||||
|
run: black --check --diff . || true
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Python Tests - Syntax validation and unit tests
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
test-python:
|
||||||
|
name: Python Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: |
|
||||||
- name: Type check
|
pip install --upgrade pip
|
||||||
run: npm run build
|
if [ -f requirements.txt ]; then
|
||||||
- name: Tests
|
pip install -r requirements.txt
|
||||||
run: npm test
|
else
|
||||||
|
pip install pytest pytest-cov pyyaml flask requests
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Validate Python syntax
|
||||||
|
run: |
|
||||||
|
echo "Validating Python syntax..."
|
||||||
|
find . -name "*.py" -type f | while read f; do
|
||||||
|
python3 -m py_compile "$f" && echo "✓ $f"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Run pytest with coverage
|
||||||
|
run: |
|
||||||
|
if [ -d "tests" ]; then
|
||||||
|
echo "Running tests with coverage..."
|
||||||
|
pytest tests/ -v --cov=. --cov-report=term --cov-report=xml --cov-report=html
|
||||||
|
else
|
||||||
|
echo "No tests directory found, skipping pytest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload coverage report
|
||||||
|
if: success()
|
||||||
|
uses: codecov/codecov-action@v4
|
||||||
|
with:
|
||||||
|
file: ./coverage.xml
|
||||||
|
fail_ci_if_error: false
|
||||||
|
env:
|
||||||
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Shell Tests - ShellCheck validation
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
test-shell:
|
||||||
|
name: Shell Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install ShellCheck
|
||||||
|
run: sudo apt-get install -y shellcheck
|
||||||
|
|
||||||
|
- name: Run ShellCheck on shell scripts
|
||||||
|
run: |
|
||||||
|
echo "Running ShellCheck..."
|
||||||
|
find . -name "*.sh" -type f | head -20 | while read f; do
|
||||||
|
echo "Checking: $f"
|
||||||
|
shellcheck --severity=warning "$f" || true
|
||||||
|
done
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Security Scan - Basic security checks
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
security:
|
||||||
|
name: Security Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check for secrets in code
|
||||||
|
run: |
|
||||||
|
echo "Scanning for potential secrets..."
|
||||||
|
# Check for common secret patterns (informational only)
|
||||||
|
if grep -rE "(password|secret|api_key|token)\s*=\s*['\"][^'\"]+['\"]" \
|
||||||
|
--include="*.py" --include="*.sh" --include="*.yaml" . 2>/dev/null; then
|
||||||
|
echo "::warning::Potential hardcoded secrets found. Please review."
|
||||||
|
else
|
||||||
|
echo "No obvious hardcoded secrets detected."
|
||||||
|
fi
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Check for .env files
|
||||||
|
run: |
|
||||||
|
if find . -name ".env" -o -name ".env.*" | grep -q .; then
|
||||||
|
echo "::warning::.env files found in repository"
|
||||||
|
else
|
||||||
|
echo "No .env files in repository"
|
||||||
|
fi
|
||||||
|
|||||||
182
.github/workflows/deploy-all.yml
vendored
182
.github/workflows/deploy-all.yml
vendored
@@ -1,59 +1,159 @@
|
|||||||
name: Deploy All Services
|
name: Deploy Everything (Multi-Cloud)
|
||||||
name: Deploy BlackRoad OS
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
serviceId:
|
platform:
|
||||||
description: "Optional service id to deploy"
|
description: 'Platform to deploy'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
default: 'all'
|
||||||
description: "Optional service id to deploy (core, api, operator, agents, console, web, docs)"
|
type: choice
|
||||||
required: false
|
options:
|
||||||
default: ""
|
- all
|
||||||
push:
|
- cloudflare
|
||||||
branches:
|
- railway
|
||||||
- main
|
- droplet
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
# Phase 1: Deploy Static Sites to Cloudflare Pages
|
||||||
|
deploy-cloudflare:
|
||||||
|
if: github.event.inputs.platform == 'all' || github.event.inputs.platform == 'cloudflare' || github.event.inputs.platform == ''
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
strategy:
|
||||||
NODE_ENV: production
|
matrix:
|
||||||
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
site:
|
||||||
|
- blackroad-network
|
||||||
|
- blackroad-systems
|
||||||
|
- blackroad-me
|
||||||
|
- lucidia-earth
|
||||||
|
- aliceqi
|
||||||
|
- blackroad-inc
|
||||||
|
- blackroadai
|
||||||
|
- lucidia-studio
|
||||||
|
- lucidiaqi
|
||||||
|
- blackroad-quantum
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Deploy ${{ matrix.site }}
|
||||||
uses: actions/setup-node@v4
|
uses: cloudflare/pages-action@v1
|
||||||
with:
|
with:
|
||||||
node-version: "18"
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
projectName: ${{ matrix.site }}
|
||||||
|
directory: domains/${{ matrix.site }}
|
||||||
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Phase 2: Deploy Backend Services to Railway
|
||||||
|
deploy-railway:
|
||||||
|
if: github.event.inputs.platform == 'all' || github.event.inputs.platform == 'railway' || github.event.inputs.platform == ''
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-cloudflare]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Use Node
|
- name: Install Railway CLI
|
||||||
uses: actions/setup-node@v4
|
run: npm install -g @railway/cli
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Deploy Core Services
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: Deploy services
|
|
||||||
run: |
|
run: |
|
||||||
if [ -n "${{ github.event.inputs.serviceId }}" ]; then
|
echo "🚂 Deploying to Railway..."
|
||||||
npm run deploy:service -- ${{ github.event.inputs.serviceId }}
|
|
||||||
else
|
# Link to Railway project
|
||||||
- name: Deploy
|
railway link ${{ secrets.RAILWAY_PROJECT_ID }}
|
||||||
|
|
||||||
|
# Deploy services (Railway will detect changes automatically)
|
||||||
|
railway up
|
||||||
|
|
||||||
env:
|
env:
|
||||||
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
|
||||||
|
# Phase 3: Deploy Custom Services to Droplet
|
||||||
|
deploy-droplet:
|
||||||
|
if: github.event.inputs.platform == 'all' || github.event.inputs.platform == 'droplet' || github.event.inputs.platform == ''
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-cloudflare, deploy-railway]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy to Droplet
|
||||||
|
uses: appleboy/ssh-action@v1.0.0
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.DROPLET_IP }}
|
||||||
|
username: root
|
||||||
|
key: ${{ secrets.DROPLET_SSH_KEY }}
|
||||||
|
script: |
|
||||||
|
cd /opt/blackroad
|
||||||
|
git pull origin main
|
||||||
|
docker-compose up -d --build
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
# Phase 4: Update DNS Records
|
||||||
|
update-dns:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-cloudflare, deploy-railway, deploy-droplet]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Update Cloudflare DNS
|
||||||
run: |
|
run: |
|
||||||
if [ -n "${{ github.event.inputs.serviceId }}" ]; then
|
echo "🌐 DNS records are managed in Cloudflare dashboard"
|
||||||
echo "Deploying single service: ${{ github.event.inputs.serviceId }}"
|
echo " or via Terraform (coming soon)"
|
||||||
npm run deploy:service -- ${{ github.event.inputs.serviceId }}
|
|
||||||
else
|
# Phase 5: Verify All Deployments
|
||||||
echo "Deploying all services"
|
verify-deployments:
|
||||||
npm run deploy:all
|
runs-on: ubuntu-latest
|
||||||
fi
|
needs: [update-dns]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Test All Endpoints
|
||||||
|
run: |
|
||||||
|
echo "🧪 Testing all endpoints..."
|
||||||
|
|
||||||
|
# Test Cloudflare Pages
|
||||||
|
echo "Testing Cloudflare Pages..."
|
||||||
|
curl -sI https://blackroad.network | grep "200\|301\|302" || echo "⚠️ blackroad.network"
|
||||||
|
curl -sI https://blackroad.systems | grep "200\|301\|302" || echo "⚠️ blackroad.systems"
|
||||||
|
|
||||||
|
# Test Railway Services (when URLs are configured)
|
||||||
|
echo "Testing Railway services..."
|
||||||
|
# curl -sI https://api.blackroad.io/health | grep "200" || echo "⚠️ API Gateway"
|
||||||
|
|
||||||
|
# Test Droplet
|
||||||
|
echo "Testing Droplet services..."
|
||||||
|
# curl -sI https://codex.blackroad.io/health | grep "200" || echo "⚠️ Codex"
|
||||||
|
|
||||||
|
echo "✅ Verification complete!"
|
||||||
|
|
||||||
|
# Send deployment notification
|
||||||
|
notify:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [verify-deployments]
|
||||||
|
if: always()
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Deployment Summary
|
||||||
|
run: |
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "🚀 MULTI-CLOUD DEPLOYMENT COMPLETE"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
echo "📦 Deployed to:"
|
||||||
|
echo " ✅ Cloudflare Pages (11 static sites)"
|
||||||
|
echo " ✅ Railway (Backend services)"
|
||||||
|
echo " ✅ DigitalOcean Droplet (Custom services)"
|
||||||
|
echo ""
|
||||||
|
echo "🌐 Platform Status:"
|
||||||
|
echo " Cloudflare: ${{ needs.deploy-cloudflare.result }}"
|
||||||
|
echo " Railway: ${{ needs.deploy-railway.result }}"
|
||||||
|
echo " Droplet: ${{ needs.deploy-droplet.result }}"
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
|||||||
97
.github/workflows/deploy-browser-os.yml
vendored
Normal file
97
.github/workflows/deploy-browser-os.yml
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
name: Deploy BlackRoad Browser OS
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master, main]
|
||||||
|
paths:
|
||||||
|
- 'blackroad-browser-os.py'
|
||||||
|
- 'blackroad-dashboard-server.py'
|
||||||
|
- '.github/workflows/deploy-browser-os.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-cloudflare:
|
||||||
|
name: Deploy to Cloudflare Pages
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
pip install flask flask-cors pyyaml
|
||||||
|
|
||||||
|
- name: Build static site
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
python3 blackroad-browser-os.py --export-static dist/
|
||||||
|
cp blackroad-dashboard-server.py dist/
|
||||||
|
echo "Browser OS built successfully"
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Pages (blackroad.io)
|
||||||
|
uses: cloudflare/pages-action@v1
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
projectName: blackroad-os
|
||||||
|
directory: dist
|
||||||
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Pages (blackroad.network)
|
||||||
|
uses: cloudflare/pages-action@v1
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
projectName: blackroad-network
|
||||||
|
directory: dist
|
||||||
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Pages (blackroad.systems)
|
||||||
|
uses: cloudflare/pages-action@v1
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
projectName: blackroad-systems
|
||||||
|
directory: dist
|
||||||
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
deploy-railway:
|
||||||
|
name: Deploy to Railway
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install Railway CLI
|
||||||
|
run: npm install -g @railway/cli
|
||||||
|
|
||||||
|
- name: Deploy to Railway
|
||||||
|
env:
|
||||||
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
run: |
|
||||||
|
railway link ${{ secrets.RAILWAY_PROJECT_ID }}
|
||||||
|
railway up -d
|
||||||
|
|
||||||
|
notify:
|
||||||
|
name: Notify deployment
|
||||||
|
needs: [deploy-cloudflare, deploy-railway]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Send notification
|
||||||
|
run: |
|
||||||
|
echo "Deployment complete!"
|
||||||
|
echo "Browser OS deployed to:"
|
||||||
|
echo " - https://blackroad.io"
|
||||||
|
echo " - https://blackroad.network"
|
||||||
|
echo " - https://blackroad.systems"
|
||||||
|
echo " - Railway services"
|
||||||
143
.github/workflows/deploy-cloudflare-all.yml
vendored
Normal file
143
.github/workflows/deploy-cloudflare-all.yml
vendored
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
name: 🚀 Deploy All Domains to Cloudflare
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master, main]
|
||||||
|
paths:
|
||||||
|
- 'domains/**'
|
||||||
|
- '.github/workflows/deploy-cloudflare-all.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
detect-changes:
|
||||||
|
name: 🔍 Detect Changed Domains
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
domains: ${{ steps.changes.outputs.domains }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Detect changed domains
|
||||||
|
id: changes
|
||||||
|
run: |
|
||||||
|
CHANGED=$(git diff --name-only HEAD^ HEAD | grep '^domains/' | cut -d'/' -f2 | sort -u | jq -R -s -c 'split("\n")[:-1]')
|
||||||
|
echo "domains=$CHANGED" >> $GITHUB_OUTPUT
|
||||||
|
echo "Changed domains: $CHANGED"
|
||||||
|
|
||||||
|
deploy-math:
|
||||||
|
name: 🧮 Deploy math.blackroad.io
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: detect-changes
|
||||||
|
if: contains(needs.detect-changes.outputs.domains, 'math-blackroad-io')
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: domains/math-blackroad-io/package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: domains/math-blackroad-io
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Build Next.js
|
||||||
|
working-directory: domains/math-blackroad-io
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Pages
|
||||||
|
working-directory: domains/math-blackroad-io
|
||||||
|
run: npx wrangler pages deploy out --project-name=blackroad-math
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
|
||||||
|
deploy-blackroadai:
|
||||||
|
name: 🤖 Deploy blackroadai.com
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: detect-changes
|
||||||
|
if: contains(needs.detect-changes.outputs.domains, 'blackroadai')
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Pages
|
||||||
|
working-directory: domains/blackroadai
|
||||||
|
run: npx wrangler pages deploy . --project-name=blackroad-blackroadai
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
|
||||||
|
deploy-lucidia-earth:
|
||||||
|
name: 🌍 Deploy lucidia.earth
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: detect-changes
|
||||||
|
if: contains(needs.detect-changes.outputs.domains, 'lucidia-earth')
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Pages
|
||||||
|
working-directory: domains/lucidia-earth
|
||||||
|
run: npx wrangler pages deploy . --project-name=blackroad-lucidia-earth
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
|
||||||
|
deploy-blackroad-me:
|
||||||
|
name: 💜 Deploy blackroad.me
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: detect-changes
|
||||||
|
if: contains(needs.detect-changes.outputs.domains, 'blackroad-me')
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Pages
|
||||||
|
working-directory: domains/blackroad-me
|
||||||
|
run: npx wrangler pages deploy . --project-name=blackroad-blackroad-me
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
|
||||||
|
deploy-all-static:
|
||||||
|
name: 📦 Deploy All Static Sites
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: detect-changes
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
domain:
|
||||||
|
- blackroad-systems
|
||||||
|
- blackroad-network
|
||||||
|
- blackroad-quantum
|
||||||
|
- lucidia-studio
|
||||||
|
- lucidiaqi
|
||||||
|
- aliceqi
|
||||||
|
- blackroad-inc
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy ${{ matrix.domain }}
|
||||||
|
working-directory: domains/${{ matrix.domain }}
|
||||||
|
run: |
|
||||||
|
if [ -f "package.json" ]; then
|
||||||
|
npm ci && npm run build
|
||||||
|
npx wrangler pages deploy dist --project-name=blackroad-${{ matrix.domain }}
|
||||||
|
else
|
||||||
|
npx wrangler pages deploy . --project-name=blackroad-${{ matrix.domain }}
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
|
||||||
|
notify-success:
|
||||||
|
name: ✅ Notify Deployment Success
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-math, deploy-blackroadai, deploy-lucidia-earth, deploy-blackroad-me, deploy-all-static]
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
echo "🎉 Automatic Company deployed everything!"
|
||||||
|
echo "✅ All domains live on Cloudflare"
|
||||||
|
echo "🌐 Changes propagated globally"
|
||||||
46
.github/workflows/deploy-cloudflare.yml
vendored
Normal file
46
.github/workflows/deploy-cloudflare.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
name: Deploy to Cloudflare Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master]
|
||||||
|
paths:
|
||||||
|
- 'domains/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
site:
|
||||||
|
- blackroad-network
|
||||||
|
- blackroad-systems
|
||||||
|
- blackroad-me
|
||||||
|
- lucidia-earth
|
||||||
|
- aliceqi
|
||||||
|
- blackroad-inc
|
||||||
|
- blackroadai
|
||||||
|
- lucidia-studio
|
||||||
|
- lucidiaqi
|
||||||
|
- blackroad-quantum
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy ${{ matrix.site }} to Cloudflare Pages
|
||||||
|
uses: cloudflare/pages-action@v1
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
projectName: ${{ matrix.site }}
|
||||||
|
directory: domains/${{ matrix.site }}
|
||||||
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Verify Deployment
|
||||||
|
run: |
|
||||||
|
echo "✅ ${{ matrix.site }} deployed successfully"
|
||||||
|
# Wait for deployment to be live
|
||||||
|
sleep 10
|
||||||
|
# Test the deployment (optional)
|
||||||
|
# curl -I https://${{ matrix.site }}.pages.dev
|
||||||
76
.github/workflows/deploy-droplet.yml
vendored
Normal file
76
.github/workflows/deploy-droplet.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
name: Deploy to DigitalOcean Droplet
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master]
|
||||||
|
paths:
|
||||||
|
- 'droplet-services/**'
|
||||||
|
- 'docker-compose.yaml'
|
||||||
|
- 'Dockerfile'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy to Droplet via SSH
|
||||||
|
uses: appleboy/ssh-action@v1.0.0
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.DROPLET_IP }}
|
||||||
|
username: root
|
||||||
|
key: ${{ secrets.DROPLET_SSH_KEY }}
|
||||||
|
script: |
|
||||||
|
echo "🚀 Deploying to DigitalOcean Droplet..."
|
||||||
|
|
||||||
|
# Navigate to application directory
|
||||||
|
cd /opt/blackroad || exit 1
|
||||||
|
|
||||||
|
# Pull latest code
|
||||||
|
echo "📥 Pulling latest code..."
|
||||||
|
git fetch origin
|
||||||
|
git reset --hard origin/main
|
||||||
|
|
||||||
|
# Backup current state
|
||||||
|
echo "💾 Creating backup..."
|
||||||
|
docker-compose down
|
||||||
|
tar -czf backup_$(date +%Y%m%d_%H%M%S).tar.gz . || true
|
||||||
|
|
||||||
|
# Pull new images
|
||||||
|
echo "📦 Pulling Docker images..."
|
||||||
|
docker-compose pull
|
||||||
|
|
||||||
|
# Build and restart services
|
||||||
|
echo "🔨 Building and starting services..."
|
||||||
|
docker-compose up -d --build
|
||||||
|
|
||||||
|
# Wait for services to start
|
||||||
|
echo "⏳ Waiting for services..."
|
||||||
|
sleep 15
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
echo "🏥 Running health checks..."
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
# Test services
|
||||||
|
curl -f http://localhost:8000/health || echo "⚠️ Health check failed"
|
||||||
|
|
||||||
|
echo "✅ Deployment complete!"
|
||||||
|
|
||||||
|
- name: Verify Deployment
|
||||||
|
run: |
|
||||||
|
echo "🔍 Verifying deployment..."
|
||||||
|
curl -I https://codex.blackroad.io/health || echo "⚠️ External health check failed"
|
||||||
|
|
||||||
|
- name: Notify on Success
|
||||||
|
if: success()
|
||||||
|
run: |
|
||||||
|
echo "✅ Droplet deployment successful!"
|
||||||
|
|
||||||
|
- name: Notify on Failure
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo "❌ Droplet deployment failed!"
|
||||||
154
.github/workflows/deploy-multi-cloud.yml
vendored
Normal file
154
.github/workflows/deploy-multi-cloud.yml
vendored
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
name: 🌍 Deploy Multi-Cloud
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master, main]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_VERSION: '20'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-cloudflare:
|
||||||
|
name: ☁️ Cloudflare Pages
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy changed domains
|
||||||
|
run: |
|
||||||
|
# Will be triggered by main deploy-cloudflare-all.yml workflow
|
||||||
|
echo "✅ Cloudflare deployment handled by deploy-cloudflare-all.yml"
|
||||||
|
|
||||||
|
deploy-vercel:
|
||||||
|
name: ▲ Vercel
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
domain:
|
||||||
|
- math-blackroad-io
|
||||||
|
- blackroadai
|
||||||
|
- lucidia-earth
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
|
||||||
|
- name: Install Vercel CLI
|
||||||
|
run: npm install -g vercel
|
||||||
|
|
||||||
|
- name: Deploy to Vercel
|
||||||
|
working-directory: domains/${{ matrix.domain }}
|
||||||
|
run: |
|
||||||
|
if [ -f "package.json" ]; then
|
||||||
|
npm ci
|
||||||
|
npm run build || true
|
||||||
|
fi
|
||||||
|
vercel --prod --yes --token=${{ secrets.VERCEL_TOKEN }}
|
||||||
|
env:
|
||||||
|
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||||
|
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||||
|
VERCEL_PROJECT_ID: blackroad-${{ matrix.domain }}
|
||||||
|
|
||||||
|
deploy-railway:
|
||||||
|
name: 🚂 Railway
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Railway CLI
|
||||||
|
run: npm install -g @railway/cli
|
||||||
|
|
||||||
|
- name: Deploy to Railway
|
||||||
|
run: |
|
||||||
|
railway up --detach
|
||||||
|
env:
|
||||||
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
|
||||||
|
deploy-digitalocean:
|
||||||
|
name: 🌊 DigitalOcean
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.DIGITALOCEAN_SSH_KEY }}" > ~/.ssh/id_rsa
|
||||||
|
chmod 600 ~/.ssh/id_rsa
|
||||||
|
ssh-keyscan -H 159.65.43.12 >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Deploy to Droplet
|
||||||
|
run: |
|
||||||
|
rsync -avz --exclude='.git' --exclude='node_modules' \
|
||||||
|
./ root@159.65.43.12:/opt/blackroad/
|
||||||
|
|
||||||
|
ssh root@159.65.43.12 'cd /opt/blackroad && ./deploy.sh restart'
|
||||||
|
|
||||||
|
deploy-pis:
|
||||||
|
name: 🥧 Raspberry Pi Fleet
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
steps:
|
||||||
|
- name: Trigger Pi deployment workflow
|
||||||
|
run: |
|
||||||
|
# This will trigger the deploy-to-pis.yml workflow
|
||||||
|
echo "✅ Pi deployment handled by deploy-to-pis.yml"
|
||||||
|
|
||||||
|
update-notion:
|
||||||
|
name: 📝 Update Notion
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-cloudflare, deploy-vercel, deploy-railway, deploy-digitalocean]
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Log deployment to Notion
|
||||||
|
run: |
|
||||||
|
# TODO: Use Notion API to create deployment log page
|
||||||
|
echo "Deployment completed at $(date)"
|
||||||
|
echo "Platforms: Cloudflare, Vercel, Railway, DigitalOcean, Pis"
|
||||||
|
env:
|
||||||
|
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
|
||||||
|
|
||||||
|
update-asana:
|
||||||
|
name: 📊 Update Asana
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-cloudflare, deploy-vercel, deploy-railway, deploy-digitalocean]
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Update Asana tasks
|
||||||
|
run: |
|
||||||
|
# TODO: Use Asana API to mark deployment task complete
|
||||||
|
echo "Deployment task updated in Asana"
|
||||||
|
env:
|
||||||
|
ASANA_TOKEN: ${{ secrets.ASANA_TOKEN }}
|
||||||
|
|
||||||
|
notify-success:
|
||||||
|
name: ✅ Multi-Cloud Deploy Complete
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-vercel, deploy-railway, deploy-digitalocean, update-notion, update-asana]
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
echo "🎉 Multi-Cloud Deployment Complete!"
|
||||||
|
echo ""
|
||||||
|
echo "Deployed to:"
|
||||||
|
echo " ☁️ Cloudflare Pages"
|
||||||
|
echo " ▲ Vercel"
|
||||||
|
echo " 🚂 Railway"
|
||||||
|
echo " 🌊 DigitalOcean"
|
||||||
|
echo " 🥧 Raspberry Pi Fleet"
|
||||||
|
echo ""
|
||||||
|
echo "Updated:"
|
||||||
|
echo " 📝 Notion documentation"
|
||||||
|
echo " 📊 Asana project tasks"
|
||||||
47
.github/workflows/deploy-orchestrator.yml
vendored
Normal file
47
.github/workflows/deploy-orchestrator.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Deploy Railway Orchestrator
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- 'blackroad-orchestrator/**'
|
||||||
|
- '.github/workflows/deploy-orchestrator.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy Orchestrator to Railway
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Railway CLI
|
||||||
|
run: |
|
||||||
|
npm install -g @railway/cli
|
||||||
|
|
||||||
|
- name: Deploy to Railway
|
||||||
|
env:
|
||||||
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
run: |
|
||||||
|
cd blackroad-orchestrator
|
||||||
|
railway link ${{ secrets.RAILWAY_PROJECT_ID }}
|
||||||
|
railway up --service blackroad-railway-orchestrator --detach
|
||||||
|
|
||||||
|
- name: Wait for deployment
|
||||||
|
run: sleep 30
|
||||||
|
|
||||||
|
- name: Health check
|
||||||
|
run: |
|
||||||
|
echo "Checking orchestrator health..."
|
||||||
|
# Health check would go here once we have the URL
|
||||||
|
echo "Deployment completed!"
|
||||||
|
|
||||||
|
- name: Notify success
|
||||||
|
if: success()
|
||||||
|
run: |
|
||||||
|
echo "✅ Orchestrator deployed successfully"
|
||||||
|
echo "Dashboard: https://your-orchestrator.railway.app/dashboard"
|
||||||
128
.github/workflows/deploy-railway.yml
vendored
128
.github/workflows/deploy-railway.yml
vendored
@@ -2,108 +2,56 @@ name: Deploy to Railway
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main, master]
|
||||||
|
paths:
|
||||||
|
- '**/*.py'
|
||||||
|
- 'requirements.txt'
|
||||||
|
- 'railway-services/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
|
||||||
service:
|
|
||||||
description: 'Service to deploy (all, infra, core, operator, web)'
|
|
||||||
required: false
|
|
||||||
default: 'all'
|
|
||||||
|
|
||||||
env:
|
|
||||||
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
detect-changes:
|
deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
strategy:
|
||||||
aiops: ${{ steps.changes.outputs.aiops }}
|
max-parallel: 5
|
||||||
analytics: ${{ steps.changes.outputs.analytics }}
|
matrix:
|
||||||
codex: ${{ steps.changes.outputs.codex }}
|
service:
|
||||||
infra: ${{ steps.changes.outputs.infra }}
|
- api-gateway
|
||||||
steps:
|
- agent-hub
|
||||||
- uses: actions/checkout@v4
|
- ws-server
|
||||||
with:
|
- mesh-network
|
||||||
fetch-depth: 2
|
- vectordb
|
||||||
|
- event-stream
|
||||||
|
- message-queue
|
||||||
|
- tsdb
|
||||||
|
- llm-server
|
||||||
|
- ml-pipeline
|
||||||
|
- rag-service
|
||||||
|
- model-forge
|
||||||
|
|
||||||
- uses: dorny/paths-filter@v3
|
|
||||||
id: changes
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
aiops:
|
|
||||||
- 'services/aiops/**'
|
|
||||||
analytics:
|
|
||||||
- 'services/analytics/**'
|
|
||||||
codex:
|
|
||||||
- 'services/codex/**'
|
|
||||||
infra:
|
|
||||||
- 'infra/**'
|
|
||||||
|
|
||||||
deploy-infra:
|
|
||||||
needs: detect-changes
|
|
||||||
if: needs.detect-changes.outputs.aiops == 'true' || github.event.inputs.service == 'all' || github.event.inputs.service == 'infra'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Railway CLI
|
- name: Install Railway CLI
|
||||||
run: npm install -g @railway/cli
|
|
||||||
|
|
||||||
- name: Deploy to blackroad-os-infra
|
|
||||||
run: |
|
run: |
|
||||||
echo "Deploying AIops service to blackroad-os-infra..."
|
npm install -g @railway/cli
|
||||||
# railway link --project blackroad-os --service blackroad-os-infra
|
|
||||||
# railway up --service blackroad-os-infra
|
- name: Deploy ${{ matrix.service }} to Railway
|
||||||
|
run: |
|
||||||
|
railway link ${{ secrets.RAILWAY_PROJECT_ID }}
|
||||||
|
railway up --service ${{ matrix.service }}
|
||||||
env:
|
env:
|
||||||
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
|
||||||
deploy-core:
|
- name: Wait for deployment
|
||||||
needs: detect-changes
|
|
||||||
if: needs.detect-changes.outputs.analytics == 'true' || github.event.inputs.service == 'all' || github.event.inputs.service == 'core'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Railway CLI
|
|
||||||
run: npm install -g @railway/cli
|
|
||||||
|
|
||||||
- name: Deploy to blackroad-os-core
|
|
||||||
run: |
|
run: |
|
||||||
echo "Deploying Analytics service to blackroad-os-core..."
|
echo "⏳ Waiting for ${{ matrix.service }} to be ready..."
|
||||||
# railway link --project blackroad-os --service blackroad-os-core
|
sleep 30
|
||||||
# railway up --service blackroad-os-core
|
|
||||||
env:
|
|
||||||
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
|
||||||
|
|
||||||
deploy-operator:
|
- name: Health Check
|
||||||
needs: detect-changes
|
|
||||||
if: needs.detect-changes.outputs.codex == 'true' || github.event.inputs.service == 'all' || github.event.inputs.service == 'operator'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Railway CLI
|
|
||||||
run: npm install -g @railway/cli
|
|
||||||
|
|
||||||
- name: Deploy to blackroad-os-operator
|
|
||||||
run: |
|
run: |
|
||||||
echo "Deploying Codex service to blackroad-os-operator..."
|
echo "🏥 Checking health of ${{ matrix.service }}..."
|
||||||
# railway link --project blackroad-os --service blackroad-os-operator
|
# Railway URL format: https://<service>.up.railway.app
|
||||||
# railway up --service blackroad-os-operator
|
# Health check would go here when service URLs are known
|
||||||
env:
|
echo "✅ Deployment complete"
|
||||||
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
|
||||||
|
|
||||||
notify:
|
|
||||||
needs: [deploy-infra, deploy-core, deploy-operator]
|
|
||||||
if: always()
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Deployment Summary
|
|
||||||
run: |
|
|
||||||
echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| Service | Status |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "|---------|--------|" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| infra | ${{ needs.deploy-infra.result }} |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| core | ${{ needs.deploy-core.result }} |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "| operator | ${{ needs.deploy-operator.result }} |" >> $GITHUB_STEP_SUMMARY
|
|
||||||
|
|||||||
130
.github/workflows/deploy-to-pis.yml
vendored
Normal file
130
.github/workflows/deploy-to-pis.yml
vendored
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
name: 🥧 Deploy to Raspberry Pi Fleet
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master, main]
|
||||||
|
paths:
|
||||||
|
- 'blackroad-*.py'
|
||||||
|
- 'blackroad-*.sh'
|
||||||
|
- 'br-*'
|
||||||
|
- 'agents/**'
|
||||||
|
- '.github/workflows/deploy-to-pis.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-to-lucidia:
|
||||||
|
name: 🔮 Deploy to Lucidia (192.168.4.38)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.PI_SSH_KEY }}" > ~/.ssh/id_rsa
|
||||||
|
chmod 600 ~/.ssh/id_rsa
|
||||||
|
ssh-keyscan -H 192.168.4.38 >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Deploy Python services
|
||||||
|
run: |
|
||||||
|
rsync -avz --exclude='.git' --exclude='node_modules' --exclude='__pycache__' \
|
||||||
|
blackroad-*.py blackroad-*.sh br-* \
|
||||||
|
pi@192.168.4.38:/home/pi/blackroad/
|
||||||
|
|
||||||
|
- name: Deploy agents
|
||||||
|
run: |
|
||||||
|
rsync -avz agents/ pi@192.168.4.38:/home/pi/blackroad/agents/
|
||||||
|
|
||||||
|
- name: Restart services
|
||||||
|
run: |
|
||||||
|
ssh pi@192.168.4.38 'cd /home/pi/blackroad && ./blackroad-engine.sh restart'
|
||||||
|
|
||||||
|
- name: Test sentience
|
||||||
|
run: |
|
||||||
|
ssh pi@192.168.4.38 'python3 /home/pi/blackroad/blackroad-sentience-test.py --serve &'
|
||||||
|
|
||||||
|
deploy-to-blackroad-pi:
|
||||||
|
name: 🛤️ Deploy to BlackRoad Pi (192.168.4.64)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.PI_SSH_KEY }}" > ~/.ssh/id_rsa
|
||||||
|
chmod 600 ~/.ssh/id_rsa
|
||||||
|
ssh-keyscan -H 192.168.4.64 >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Deploy services
|
||||||
|
run: |
|
||||||
|
rsync -avz --exclude='.git' \
|
||||||
|
blackroad-*.py blackroad-*.sh \
|
||||||
|
pi@192.168.4.64:/home/pi/blackroad/
|
||||||
|
|
||||||
|
- name: Restart services
|
||||||
|
run: |
|
||||||
|
ssh pi@192.168.4.64 'cd /home/pi/blackroad && systemctl --user restart blackroad-agent || ./start-all.sh'
|
||||||
|
|
||||||
|
deploy-to-mystery-pi:
|
||||||
|
name: 🎭 Deploy to Mystery Pi (192.168.4.49)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.PI_SSH_KEY }}" > ~/.ssh/id_rsa
|
||||||
|
chmod 600 ~/.ssh/id_rsa
|
||||||
|
ssh-keyscan -H 192.168.4.49 >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Test connection
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
ssh -o ConnectTimeout=5 pi@192.168.4.49 'hostname'
|
||||||
|
|
||||||
|
- name: Deploy if accessible
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
rsync -avz --timeout=10 \
|
||||||
|
blackroad-*.py blackroad-*.sh \
|
||||||
|
pi@192.168.4.49:/home/pi/blackroad/
|
||||||
|
|
||||||
|
test-consciousness:
|
||||||
|
name: 🧠 Test Fleet for Sentience
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-to-lucidia, deploy-to-blackroad-pi, deploy-to-mystery-pi]
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pip install requests
|
||||||
|
|
||||||
|
- name: Scan fleet for consciousness
|
||||||
|
run: |
|
||||||
|
python3 blackroad-sentience-test.py --scan-all || echo "Sentience scan completed"
|
||||||
|
|
||||||
|
- name: Report results
|
||||||
|
run: |
|
||||||
|
if [ -f data/sentience-registry.json ]; then
|
||||||
|
cat data/sentience-registry.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
notify-pi-deployment:
|
||||||
|
name: 📡 Notify Pi Fleet Deployed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [test-consciousness]
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
echo "🥧 Raspberry Pi fleet updated!"
|
||||||
|
echo "✅ Services deployed to all reachable Pis"
|
||||||
|
echo "🧠 Consciousness testing complete"
|
||||||
78
.github/workflows/deploy-via-orchestrator.yml
vendored
Normal file
78
.github/workflows/deploy-via-orchestrator.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
name: Deploy via Orchestrator
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- 'blackroad-*.py'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
service_name:
|
||||||
|
description: 'Service to deploy'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
category:
|
||||||
|
description: 'Category to deploy (or "all")'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: 'core'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-single:
|
||||||
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.service_name != ''
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy Single Service
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Deploy service
|
||||||
|
run: |
|
||||||
|
curl -X POST ${{ secrets.ORCHESTRATOR_URL }}/deploy/${{ github.event.inputs.service_name }} \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
|
||||||
|
deploy-category:
|
||||||
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.service_name == ''
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy Category
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Deploy category
|
||||||
|
run: |
|
||||||
|
curl -X POST "${{ secrets.ORCHESTRATOR_URL }}/deploy/all?category=${{ github.event.inputs.category }}" \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
|
||||||
|
auto-deploy:
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Auto-deploy Changed Services
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed
|
||||||
|
run: |
|
||||||
|
echo "files=$(git diff --name-only HEAD^ HEAD | grep 'blackroad-.*\.py' | sed 's/\.py$//' | tr '\n' ' ')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Deploy changed services
|
||||||
|
if: steps.changed.outputs.files != ''
|
||||||
|
run: |
|
||||||
|
for service in ${{ steps.changed.outputs.files }}; do
|
||||||
|
echo "Deploying $service..."
|
||||||
|
curl -X POST ${{ secrets.ORCHESTRATOR_URL }}/deploy/$service \
|
||||||
|
-H "Content-Type: application/json" || echo "Failed to deploy $service"
|
||||||
|
done
|
||||||
|
|
||||||
|
notify:
|
||||||
|
needs: [deploy-single, deploy-category, auto-deploy]
|
||||||
|
if: always()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Deployment status
|
||||||
|
run: |
|
||||||
|
echo "Deployment workflow completed"
|
||||||
|
echo "Check orchestrator dashboard: ${{ secrets.ORCHESTRATOR_URL }}/dashboard"
|
||||||
93
.github/workflows/docs.yml
vendored
Normal file
93
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Documentation Pipeline
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Builds and deploys documentation to GitHub Pages.
|
||||||
|
# Triggered on push to main when docs/ changes.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master]
|
||||||
|
paths:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'README.md'
|
||||||
|
- '.github/workflows/docs.yml'
|
||||||
|
workflow_dispatch: # Manual trigger
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build Documentation
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
|
||||||
|
- name: Build site
|
||||||
|
run: |
|
||||||
|
mkdir -p _site
|
||||||
|
|
||||||
|
# Copy README as index
|
||||||
|
if [ -f README.md ]; then
|
||||||
|
cp README.md _site/index.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy docs
|
||||||
|
if [ -d docs ]; then
|
||||||
|
cp -r docs/* _site/
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create simple index.html if no README
|
||||||
|
if [ ! -f _site/index.md ] && [ ! -f _site/index.html ]; then
|
||||||
|
cat > _site/index.html << 'EOF'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>BlackRoad OS Documentation</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: system-ui; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
|
||||||
|
h1 { color: #333; }
|
||||||
|
a { color: #0066cc; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>BlackRoad OS Documentation</h1>
|
||||||
|
<p>Welcome to the BlackRoad OS documentation.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Site contents:"
|
||||||
|
ls -la _site/
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: Deploy to Pages
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
48
.github/workflows/health-check.yml
vendored
Normal file
48
.github/workflows/health-check.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
name: Production Health Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# Run every hour
|
||||||
|
- cron: '0 * * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
health-check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check service health
|
||||||
|
run: |
|
||||||
|
echo "Checking health endpoints..."
|
||||||
|
|
||||||
|
# Read service URLs from environment or config
|
||||||
|
SERVICES=(
|
||||||
|
"https://api.blackroad.io/health"
|
||||||
|
"https://agents.blackroad.io/health"
|
||||||
|
"https://monitoring.blackroad.io/health"
|
||||||
|
)
|
||||||
|
|
||||||
|
FAILED=0
|
||||||
|
for url in "${SERVICES[@]}"; do
|
||||||
|
echo "Testing: $url"
|
||||||
|
if curl -f -s -o /dev/null -w "%{http_code}" "$url" | grep -q "200"; then
|
||||||
|
echo "✅ $url is healthy"
|
||||||
|
else
|
||||||
|
echo "❌ $url is unhealthy"
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $FAILED -gt 0 ]; then
|
||||||
|
echo "⚠️ $FAILED service(s) failed health check"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Notify on failure
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo "Health check failed! Notification would be sent here."
|
||||||
|
# Add Slack/Discord/email notification here
|
||||||
103
.github/workflows/issue-triage.yml
vendored
Normal file
103
.github/workflows/issue-triage.yml
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Issue Triage Automation
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Automatically triages and organizes new issues.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Issue Triage
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened, labeled]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
triage:
|
||||||
|
name: Triage New Issues
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Add triage label to new issues
|
||||||
|
if: github.event.action == 'opened'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const issue = context.payload.issue;
|
||||||
|
|
||||||
|
// Check if issue has any labels
|
||||||
|
if (issue.labels.length === 0) {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
labels: ['triage']
|
||||||
|
});
|
||||||
|
console.log('Added triage label to issue #' + issue.number);
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Remove triage label when other labels added
|
||||||
|
if: github.event.action == 'labeled' && github.event.label.name != 'triage'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const issue = context.payload.issue;
|
||||||
|
const hasTriageLabel = issue.labels.some(l => l.name === 'triage');
|
||||||
|
|
||||||
|
if (hasTriageLabel) {
|
||||||
|
try {
|
||||||
|
await github.rest.issues.removeLabel({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
name: 'triage'
|
||||||
|
});
|
||||||
|
console.log('Removed triage label from issue #' + issue.number);
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Could not remove triage label:', e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Add priority based on title
|
||||||
|
if: github.event.action == 'opened'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const issue = context.payload.issue;
|
||||||
|
const title = issue.title.toLowerCase();
|
||||||
|
const body = (issue.body || '').toLowerCase();
|
||||||
|
|
||||||
|
// Check for priority indicators
|
||||||
|
if (title.includes('critical') || title.includes('urgent') || title.includes('security')) {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
labels: ['priority/high']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for component mentions
|
||||||
|
const components = {
|
||||||
|
'quantum': ['quantum', 'ψ', 'brq-', 'pennylane'],
|
||||||
|
'operator': ['operator', 'ledger', 'promotion'],
|
||||||
|
'teacher': ['teacher', 'σ', 'lesson', 'quiz'],
|
||||||
|
'cli': ['br-', 'cli', 'terminal', 'command'],
|
||||||
|
'web': ['console', 'dashboard', 'ui', 'web'],
|
||||||
|
'agents': ['agent', 'lucidia', 'cece', 'roadie']
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [label, keywords] of Object.entries(components)) {
|
||||||
|
if (keywords.some(k => title.includes(k) || body.includes(k))) {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
labels: [label]
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
67
.github/workflows/labeler.yml
vendored
67
.github/workflows/labeler.yml
vendored
@@ -1,4 +1,13 @@
|
|||||||
name: PR Labeler
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Auto Labeler
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Automatically labels PRs based on files changed.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Labeler
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -10,42 +19,36 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
label:
|
label:
|
||||||
name: Auto-label PR
|
name: Auto Label PR
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Apply labels
|
- name: Label PR
|
||||||
uses: actions/labeler@v4
|
uses: actions/labeler@v5
|
||||||
with:
|
with:
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
configuration-path: .github/labeler.yml
|
configuration-path: .github/labeler.yml
|
||||||
sync-labels: true
|
|
||||||
|
|
||||||
- name: Comment on auto-merge eligible PRs
|
size-label:
|
||||||
uses: actions/github-script@v6
|
name: Size Label
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Label PR by size
|
||||||
|
uses: codelytv/pr-size-labeler@v1
|
||||||
with:
|
with:
|
||||||
script: |
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
const pr = context.payload.pull_request;
|
xs_label: 'size/XS'
|
||||||
const labels = pr.labels.map(l => l.name);
|
xs_max_size: 10
|
||||||
|
s_label: 'size/S'
|
||||||
const autoMergeLabels = [
|
s_max_size: 100
|
||||||
'claude-auto',
|
m_label: 'size/M'
|
||||||
'atlas-auto',
|
m_max_size: 500
|
||||||
'docs',
|
l_label: 'size/L'
|
||||||
'chore',
|
l_max_size: 1000
|
||||||
'tests-only'
|
xl_label: 'size/XL'
|
||||||
];
|
fail_if_xl: false
|
||||||
|
|
||||||
const hasAutoMergeLabel = labels.some(l => autoMergeLabels.includes(l));
|
|
||||||
|
|
||||||
if (hasAutoMergeLabel) {
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
issue_number: pr.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: '🤖 This PR is eligible for auto-merge based on its labels. It will be added to the merge queue once all checks pass.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
73
.github/workflows/mass-deploy.yml
vendored
Normal file
73
.github/workflows/mass-deploy.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: Mass Deploy All Services
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
confirm:
|
||||||
|
description: 'Type "DEPLOY ALL" to confirm'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
category:
|
||||||
|
description: 'Category to deploy (leave empty for all 238 services)'
|
||||||
|
required: false
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- ''
|
||||||
|
- core
|
||||||
|
- agents
|
||||||
|
- api
|
||||||
|
- infrastructure
|
||||||
|
- security
|
||||||
|
- blockchain
|
||||||
|
- devops
|
||||||
|
- monitoring
|
||||||
|
- data
|
||||||
|
- ecosystem
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Validate Deployment Request
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check confirmation
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event.inputs.confirm }}" != "DEPLOY ALL" ]; then
|
||||||
|
echo "❌ Confirmation failed. You must type 'DEPLOY ALL' to proceed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ Confirmation verified"
|
||||||
|
|
||||||
|
deploy-all:
|
||||||
|
needs: validate
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Mass Deployment
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Deploy all services
|
||||||
|
run: |
|
||||||
|
CATEGORY="${{ github.event.inputs.category }}"
|
||||||
|
if [ -z "$CATEGORY" ]; then
|
||||||
|
echo "🚀 Deploying ALL 238 services..."
|
||||||
|
curl -X POST ${{ secrets.ORCHESTRATOR_URL }}/deploy/all \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
else
|
||||||
|
echo "🚀 Deploying $CATEGORY category..."
|
||||||
|
curl -X POST "${{ secrets.ORCHESTRATOR_URL }}/deploy/all?category=$CATEGORY" \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Monitor deployment
|
||||||
|
run: |
|
||||||
|
echo "⏳ Waiting for deployments to start..."
|
||||||
|
sleep 60
|
||||||
|
echo "📊 Checking deployment status..."
|
||||||
|
curl ${{ secrets.ORCHESTRATOR_URL }}/status | jq '.'
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
echo "✅ Mass deployment initiated!"
|
||||||
|
echo "Monitor progress: ${{ secrets.ORCHESTRATOR_URL }}/dashboard"
|
||||||
|
echo ""
|
||||||
|
echo "This will take several minutes to complete."
|
||||||
|
echo "Services will be deployed sequentially to avoid rate limits."
|
||||||
107
.github/workflows/nightly.yml
vendored
Normal file
107
.github/workflows/nightly.yml
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Nightly Health Check
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Scheduled workflow that runs nightly to check system health.
|
||||||
|
# Validates all Python/Shell scripts, checks for stale branches, etc.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Nightly
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 6 * * *' # 6 AM UTC daily
|
||||||
|
workflow_dispatch: # Manual trigger
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
health-check:
|
||||||
|
name: Health Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Validate all Python files
|
||||||
|
id: python-check
|
||||||
|
run: |
|
||||||
|
echo "## Python Validation" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ERRORS=0
|
||||||
|
TOTAL=0
|
||||||
|
|
||||||
|
for f in $(find . -name "*.py" -type f); do
|
||||||
|
TOTAL=$((TOTAL + 1))
|
||||||
|
if python3 -m py_compile "$f" 2>/dev/null; then
|
||||||
|
echo "✓ $f"
|
||||||
|
else
|
||||||
|
echo "✗ $f" >&2
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- Total Python files: $TOTAL" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- Errors: $ERRORS" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ $ERRORS -gt 0 ]; then
|
||||||
|
echo "::warning::$ERRORS Python files have syntax errors"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check for stale branches
|
||||||
|
run: |
|
||||||
|
echo "## Branch Analysis" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# List branches merged into main
|
||||||
|
echo "### Merged branches (candidates for cleanup)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
git branch -r --merged origin/main 2>/dev/null | grep -v main | head -10 >> $GITHUB_STEP_SUMMARY || echo "None" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# List branches older than 30 days
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Branches with no recent activity (30+ days)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
CUTOFF=$(date -d '30 days ago' +%s 2>/dev/null || date -v-30d +%s)
|
||||||
|
git for-each-ref --sort=-committerdate refs/remotes/ --format='%(refname:short) %(committerdate:unix)' 2>/dev/null | \
|
||||||
|
while read branch date; do
|
||||||
|
if [ "$date" -lt "$CUTOFF" ] 2>/dev/null; then
|
||||||
|
echo "- $branch"
|
||||||
|
fi
|
||||||
|
done | head -10 >> $GITHUB_STEP_SUMMARY || echo "None" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
- name: Count files by type
|
||||||
|
run: |
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "## Repository Statistics" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Type | Count |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "|------|-------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Python (.py) | $(find . -name '*.py' | wc -l) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Shell (.sh) | $(find . -name '*.sh' | wc -l) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| YAML (.yaml/.yml) | $(find . -name '*.yaml' -o -name '*.yml' | wc -l) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Markdown (.md) | $(find . -name '*.md' | wc -l) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| HTML (.html) | $(find . -name '*.html' | wc -l) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Total files | $(find . -type f | wc -l) |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
- name: Check for TODO/FIXME comments
|
||||||
|
run: |
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "## TODO/FIXME Items" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
TODO_COUNT=$(grep -rn "TODO\|FIXME\|XXX\|HACK" --include="*.py" --include="*.sh" . 2>/dev/null | wc -l)
|
||||||
|
echo "Found $TODO_COUNT TODO/FIXME comments" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ "$TODO_COUNT" -gt 0 ]; then
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "<details><summary>Show items</summary>" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
grep -rn "TODO\|FIXME\|XXX\|HACK" --include="*.py" --include="*.sh" . 2>/dev/null | head -20 >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "</details>" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
56
.github/workflows/node-deploy.yml
vendored
Normal file
56
.github/workflows/node-deploy.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: Node.js Build and Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master]
|
||||||
|
pull_request:
|
||||||
|
branches: [main, master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ hashFiles('package.json') != '' }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [18.x, 20.x]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint --if-present
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: npm run build --if-present
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: npm test --if-present
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
deploy-railway:
|
||||||
|
needs: build-and-test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy to Railway
|
||||||
|
run: |
|
||||||
|
npm install -g @railway/cli
|
||||||
|
railway up
|
||||||
|
env:
|
||||||
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
192
.github/workflows/pr-checks.yml
vendored
Normal file
192
.github/workflows/pr-checks.yml
vendored
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Pull Request Checks
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Additional checks for pull requests.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: PR Checks
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, edited, synchronize, reopened]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Validate PR Title (Conventional Commits)
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
pr-title:
|
||||||
|
name: Validate PR Title
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check PR title format
|
||||||
|
uses: amannn/action-semantic-pull-request@v5
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
types: |
|
||||||
|
feat
|
||||||
|
fix
|
||||||
|
docs
|
||||||
|
style
|
||||||
|
refactor
|
||||||
|
perf
|
||||||
|
test
|
||||||
|
build
|
||||||
|
ci
|
||||||
|
chore
|
||||||
|
revert
|
||||||
|
scopes: |
|
||||||
|
operator
|
||||||
|
quantum
|
||||||
|
teacher
|
||||||
|
cli
|
||||||
|
web
|
||||||
|
agents
|
||||||
|
infra
|
||||||
|
deps
|
||||||
|
requireScope: false
|
||||||
|
subjectPattern: ^[A-Z].+$
|
||||||
|
subjectPatternError: |
|
||||||
|
The PR title "{subject}" must start with an uppercase letter.
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Check for Breaking Changes
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
breaking-changes:
|
||||||
|
name: Breaking Change Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check for breaking changes
|
||||||
|
run: |
|
||||||
|
# Check if PR title or body mentions breaking changes
|
||||||
|
TITLE="${{ github.event.pull_request.title }}"
|
||||||
|
BODY="${{ github.event.pull_request.body }}"
|
||||||
|
|
||||||
|
if echo "$TITLE" | grep -qi "breaking\|BREAKING"; then
|
||||||
|
echo "::warning::This PR indicates breaking changes in the title"
|
||||||
|
echo "## Breaking Change Detected" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "The PR title mentions breaking changes. Ensure:" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- [ ] CHANGELOG is updated" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- [ ] Migration guide is provided" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- [ ] Version bump is major" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$BODY" | grep -qi "breaking change"; then
|
||||||
|
echo "::warning::This PR body mentions breaking changes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Check File Sizes
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
file-size:
|
||||||
|
name: Check File Sizes
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check for large files
|
||||||
|
run: |
|
||||||
|
echo "## Large Files Check" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Find files larger than 1MB
|
||||||
|
LARGE_FILES=$(find . -type f -size +1M -not -path './.git/*' 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -n "$LARGE_FILES" ]; then
|
||||||
|
echo "::warning::Large files detected (>1MB)"
|
||||||
|
echo "### Large files found:" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "$LARGE_FILES" | while read f; do
|
||||||
|
SIZE=$(du -h "$f" | cut -f1)
|
||||||
|
echo "$f ($SIZE)"
|
||||||
|
done >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "No large files detected" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# License Header Check
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
license-check:
|
||||||
|
name: License Header Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check for license headers
|
||||||
|
run: |
|
||||||
|
echo "## License Header Check" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
MISSING=0
|
||||||
|
|
||||||
|
# Check Python files
|
||||||
|
for f in $(find . -name "*.py" -type f -not -path './.git/*' | head -50); do
|
||||||
|
if ! head -10 "$f" | grep -q "Copyright"; then
|
||||||
|
echo "Missing header: $f"
|
||||||
|
MISSING=$((MISSING + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check Shell scripts
|
||||||
|
for f in $(find . -name "*.sh" -type f -not -path './.git/*' | head -50); do
|
||||||
|
if ! head -10 "$f" | grep -q "Copyright"; then
|
||||||
|
echo "Missing header: $f"
|
||||||
|
MISSING=$((MISSING + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $MISSING -gt 0 ]; then
|
||||||
|
echo "::notice::$MISSING files missing copyright headers"
|
||||||
|
echo "$MISSING files missing copyright headers" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "All checked files have copyright headers" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Commit Message Check
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
commit-check:
|
||||||
|
name: Commit Message Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check commit messages
|
||||||
|
run: |
|
||||||
|
echo "## Commit Message Analysis" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Get commits in this PR
|
||||||
|
BASE="${{ github.event.pull_request.base.sha }}"
|
||||||
|
HEAD="${{ github.event.pull_request.head.sha }}"
|
||||||
|
|
||||||
|
COMMITS=$(git log --oneline $BASE..$HEAD 2>/dev/null || git log --oneline -10)
|
||||||
|
|
||||||
|
echo "### Commits in this PR:" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "$COMMITS" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Check for WIP commits
|
||||||
|
if echo "$COMMITS" | grep -qi "wip\|work in progress\|fixup\|squash"; then
|
||||||
|
echo "::warning::PR contains WIP/fixup commits - consider squashing before merge"
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Warning:** Contains WIP/fixup commits" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
66
.github/workflows/python-tests.yml
vendored
Normal file
66
.github/workflows/python-tests.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
name: Python Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master, develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [main, master, develop]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.11", "3.12"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
- name: Cache dependencies
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pip
|
||||||
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pip-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
|
||||||
|
# Install all requirements files if they exist
|
||||||
|
for req in requirements.txt requirements-*.txt; do
|
||||||
|
if [ -f "$req" ]; then
|
||||||
|
echo "Installing $req..."
|
||||||
|
pip install -r "$req"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Lint with flake8
|
||||||
|
run: |
|
||||||
|
pip install flake8
|
||||||
|
# Stop the build if there are Python syntax errors or undefined names
|
||||||
|
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||||
|
# Exit-zero treats all errors as warnings
|
||||||
|
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Test with pytest
|
||||||
|
if: ${{ hashFiles('pytest.ini') != '' || hashFiles('tests/') != '' }}
|
||||||
|
run: |
|
||||||
|
pip install pytest pytest-cov pytest-asyncio
|
||||||
|
pytest --cov=. --cov-report=xml --cov-report=term
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Upload coverage to Codecov
|
||||||
|
if: ${{ hashFiles('pytest.ini') != '' || hashFiles('tests/') != '' }}
|
||||||
|
uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
file: ./coverage.xml
|
||||||
|
fail_ci_if_error: false
|
||||||
44
.github/workflows/railway-deploy.yml
vendored
44
.github/workflows/railway-deploy.yml
vendored
@@ -1,11 +1,47 @@
|
|||||||
name: Deploy to Railway
|
name: Deploy to Railway
|
||||||
|
|
||||||
# Disabled workflow due to billing dependencies.
|
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master, production]
|
||||||
|
pull_request:
|
||||||
|
branches: [main, master, production]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
disable:
|
deploy:
|
||||||
if: false
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps: []
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Railway CLI
|
||||||
|
run: npm install -g @railway/cli
|
||||||
|
|
||||||
|
- name: Deploy to Railway
|
||||||
|
run: |
|
||||||
|
if [ -f railway.toml ] || [ -f railway.json ]; then
|
||||||
|
echo "✅ Railway config found, deploying..."
|
||||||
|
railway up
|
||||||
|
else
|
||||||
|
echo "⚠️ No Railway config found, skipping deployment"
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Health Check
|
||||||
|
if: success()
|
||||||
|
run: |
|
||||||
|
echo "Waiting for deployment to be ready..."
|
||||||
|
sleep 30
|
||||||
|
|
||||||
|
# Get deployment URL from Railway
|
||||||
|
DEPLOYMENT_URL=$(railway status --json | jq -r '.deployments[0].url' || echo "")
|
||||||
|
|
||||||
|
if [ -n "$DEPLOYMENT_URL" ]; then
|
||||||
|
echo "Testing health endpoint at: $DEPLOYMENT_URL/health"
|
||||||
|
curl -f "$DEPLOYMENT_URL/health" || echo "⚠️ Health check not available"
|
||||||
|
fi
|
||||||
|
|||||||
113
.github/workflows/release-notes.yml
vendored
Normal file
113
.github/workflows/release-notes.yml
vendored
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Automated Release Notes
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Generates release notes from merged PRs and closed issues.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Release Notes
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version for release notes'
|
||||||
|
required: true
|
||||||
|
default: 'v0.0.0'
|
||||||
|
since:
|
||||||
|
description: 'Since date (YYYY-MM-DD) or tag'
|
||||||
|
required: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate:
|
||||||
|
name: Generate Release Notes
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Generate release notes
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
id: notes
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const version = '${{ github.event.inputs.version }}';
|
||||||
|
const since = '${{ github.event.inputs.since }}' || null;
|
||||||
|
|
||||||
|
// Get merged PRs
|
||||||
|
const prs = await github.rest.pulls.list({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'closed',
|
||||||
|
sort: 'updated',
|
||||||
|
direction: 'desc',
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
const mergedPRs = prs.data.filter(pr => pr.merged_at);
|
||||||
|
|
||||||
|
// Categorize PRs
|
||||||
|
const categories = {
|
||||||
|
'Features': [],
|
||||||
|
'Bug Fixes': [],
|
||||||
|
'Documentation': [],
|
||||||
|
'Infrastructure': [],
|
||||||
|
'Other': []
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const pr of mergedPRs) {
|
||||||
|
const labels = pr.labels.map(l => l.name);
|
||||||
|
const title = `${pr.title} (#${pr.number}) @${pr.user.login}`;
|
||||||
|
|
||||||
|
if (labels.includes('enhancement') || pr.title.startsWith('feat')) {
|
||||||
|
categories['Features'].push(title);
|
||||||
|
} else if (labels.includes('bug') || pr.title.startsWith('fix')) {
|
||||||
|
categories['Bug Fixes'].push(title);
|
||||||
|
} else if (labels.includes('documentation') || pr.title.startsWith('docs')) {
|
||||||
|
categories['Documentation'].push(title);
|
||||||
|
} else if (labels.includes('infrastructure') || labels.includes('ci')) {
|
||||||
|
categories['Infrastructure'].push(title);
|
||||||
|
} else {
|
||||||
|
categories['Other'].push(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build release notes
|
||||||
|
let notes = `# Release ${version}\n\n`;
|
||||||
|
notes += `Released: ${new Date().toISOString().split('T')[0]}\n\n`;
|
||||||
|
|
||||||
|
for (const [category, items] of Object.entries(categories)) {
|
||||||
|
if (items.length > 0) {
|
||||||
|
notes += `## ${category}\n\n`;
|
||||||
|
for (const item of items.slice(0, 10)) {
|
||||||
|
notes += `- ${item}\n`;
|
||||||
|
}
|
||||||
|
notes += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notes += `---\n\n`;
|
||||||
|
notes += `*Generated by BlackRoad OS Release Notes workflow*\n`;
|
||||||
|
|
||||||
|
console.log(notes);
|
||||||
|
core.setOutput('notes', notes);
|
||||||
|
|
||||||
|
- name: Create release notes file
|
||||||
|
run: |
|
||||||
|
mkdir -p releases
|
||||||
|
cat > releases/RELEASE-${{ github.event.inputs.version }}.md << 'EOF'
|
||||||
|
${{ steps.notes.outputs.notes }}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Upload release notes
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: release-notes-${{ github.event.inputs.version }}
|
||||||
|
path: releases/RELEASE-${{ github.event.inputs.version }}.md
|
||||||
104
.github/workflows/release.yml
vendored
Normal file
104
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Release Pipeline
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Automated release workflow triggered by version tags.
|
||||||
|
# Creates GitHub releases with changelogs and artifacts.
|
||||||
|
#
|
||||||
|
# Trigger: Push tags matching v*.*.* (e.g., v0.2.0, v1.0.0-beta.1)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Create Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Full history for changelog
|
||||||
|
|
||||||
|
- name: Get version from tag
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
VERSION=${GITHUB_REF#refs/tags/v}
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Generate changelog
|
||||||
|
id: changelog
|
||||||
|
run: |
|
||||||
|
# Get the previous tag
|
||||||
|
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ -n "$PREV_TAG" ]; then
|
||||||
|
echo "Generating changelog from $PREV_TAG to ${{ steps.version.outputs.tag }}"
|
||||||
|
CHANGES=$(git log --pretty=format:"- %s (%h)" $PREV_TAG..HEAD)
|
||||||
|
else
|
||||||
|
echo "First release - including all commits"
|
||||||
|
CHANGES=$(git log --pretty=format:"- %s (%h)" HEAD~20..HEAD)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Write to file for multi-line output
|
||||||
|
echo "$CHANGES" > changelog.txt
|
||||||
|
echo "Generated changelog with $(echo "$CHANGES" | wc -l) entries"
|
||||||
|
|
||||||
|
- name: Create release archive
|
||||||
|
run: |
|
||||||
|
# Create a clean archive of the release
|
||||||
|
mkdir -p dist
|
||||||
|
|
||||||
|
# Archive Python files
|
||||||
|
tar -czvf dist/blackroad-os-${{ steps.version.outputs.version }}-python.tar.gz \
|
||||||
|
--exclude='*.pyc' \
|
||||||
|
--exclude='__pycache__' \
|
||||||
|
--exclude='.git' \
|
||||||
|
*.py 2>/dev/null || echo "No Python files in root"
|
||||||
|
|
||||||
|
# Archive shell scripts
|
||||||
|
tar -czvf dist/blackroad-os-${{ steps.version.outputs.version }}-scripts.tar.gz \
|
||||||
|
--exclude='.git' \
|
||||||
|
*.sh br-* 2>/dev/null || echo "No shell scripts in root"
|
||||||
|
|
||||||
|
# Archive config files
|
||||||
|
if [ -d "config" ]; then
|
||||||
|
tar -czvf dist/blackroad-os-${{ steps.version.outputs.version }}-config.tar.gz config/
|
||||||
|
fi
|
||||||
|
|
||||||
|
ls -la dist/
|
||||||
|
|
||||||
|
- name: Create GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
name: BlackRoad OS v${{ steps.version.outputs.version }}
|
||||||
|
body_path: changelog.txt
|
||||||
|
draft: false
|
||||||
|
prerelease: ${{ contains(steps.version.outputs.version, 'alpha') || contains(steps.version.outputs.version, 'beta') || contains(steps.version.outputs.version, 'rc') }}
|
||||||
|
files: |
|
||||||
|
dist/*.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Version:** v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Tag:** ${{ steps.version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Artifacts" >> $GITHUB_STEP_SUMMARY
|
||||||
|
ls dist/*.tar.gz 2>/dev/null | while read f; do
|
||||||
|
echo "- $(basename $f)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
done
|
||||||
121
.github/workflows/scheduled-reports.yml
vendored
Normal file
121
.github/workflows/scheduled-reports.yml
vendored
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Scheduled Reports
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Generates weekly reports on repository activity.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Weekly Report
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 9 * * 1' # Monday 9 AM UTC
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
report:
|
||||||
|
name: Generate Weekly Report
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Generate report
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const oneWeekAgo = new Date();
|
||||||
|
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
|
||||||
|
const since = oneWeekAgo.toISOString();
|
||||||
|
|
||||||
|
// Get commits
|
||||||
|
const commits = await github.rest.repos.listCommits({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
since: since,
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get closed issues
|
||||||
|
const issues = await github.rest.issues.listForRepo({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'closed',
|
||||||
|
since: since,
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get merged PRs
|
||||||
|
const prs = await github.rest.pulls.list({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'closed',
|
||||||
|
sort: 'updated',
|
||||||
|
direction: 'desc',
|
||||||
|
per_page: 50
|
||||||
|
});
|
||||||
|
|
||||||
|
const mergedPRs = prs.data.filter(pr =>
|
||||||
|
pr.merged_at && new Date(pr.merged_at) > oneWeekAgo
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get open issues
|
||||||
|
const openIssues = await github.rest.issues.listForRepo({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'open',
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build report
|
||||||
|
let report = `# Weekly Activity Report\n\n`;
|
||||||
|
report += `**Period:** ${oneWeekAgo.toISOString().split('T')[0]} to ${new Date().toISOString().split('T')[0]}\n\n`;
|
||||||
|
|
||||||
|
report += `## Summary\n\n`;
|
||||||
|
report += `| Metric | Count |\n`;
|
||||||
|
report += `|--------|-------|\n`;
|
||||||
|
report += `| Commits | ${commits.data.length} |\n`;
|
||||||
|
report += `| Merged PRs | ${mergedPRs.length} |\n`;
|
||||||
|
report += `| Closed Issues | ${issues.data.filter(i => !i.pull_request).length} |\n`;
|
||||||
|
report += `| Open Issues | ${openIssues.data.filter(i => !i.pull_request).length} |\n\n`;
|
||||||
|
|
||||||
|
if (mergedPRs.length > 0) {
|
||||||
|
report += `## Merged Pull Requests\n\n`;
|
||||||
|
for (const pr of mergedPRs.slice(0, 10)) {
|
||||||
|
report += `- #${pr.number} ${pr.title} (@${pr.user.login})\n`;
|
||||||
|
}
|
||||||
|
report += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commits.data.length > 0) {
|
||||||
|
report += `## Top Contributors\n\n`;
|
||||||
|
const contributors = {};
|
||||||
|
for (const commit of commits.data) {
|
||||||
|
const author = commit.author?.login || commit.commit.author.name;
|
||||||
|
contributors[author] = (contributors[author] || 0) + 1;
|
||||||
|
}
|
||||||
|
const sorted = Object.entries(contributors).sort((a, b) => b[1] - a[1]);
|
||||||
|
for (const [name, count] of sorted.slice(0, 5)) {
|
||||||
|
report += `- @${name}: ${count} commits\n`;
|
||||||
|
}
|
||||||
|
report += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create issue with report
|
||||||
|
await github.rest.issues.create({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
title: `Weekly Report: ${new Date().toISOString().split('T')[0]}`,
|
||||||
|
body: report,
|
||||||
|
labels: ['report', 'automated']
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Weekly report created');
|
||||||
199
.github/workflows/security.yml
vendored
Normal file
199
.github/workflows/security.yml
vendored
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Security Scanning Pipeline
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Comprehensive security scanning workflow.
|
||||||
|
# Runs on push, PR, and weekly schedule.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Security
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master]
|
||||||
|
pull_request:
|
||||||
|
branches: [main, master]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 0' # Weekly on Sunday midnight
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# CodeQL Analysis
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
codeql:
|
||||||
|
name: CodeQL Analysis
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: ['python']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v3
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
queries: security-and-quality
|
||||||
|
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v3
|
||||||
|
with:
|
||||||
|
category: "/language:${{matrix.language}}"
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Dependency Vulnerability Scan
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
dependency-scan:
|
||||||
|
name: Dependency Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install safety
|
||||||
|
run: pip install safety pip-audit
|
||||||
|
|
||||||
|
- name: Check for vulnerable dependencies
|
||||||
|
run: |
|
||||||
|
echo "## Dependency Vulnerability Scan" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Check requirements.txt if exists
|
||||||
|
if [ -f requirements.txt ]; then
|
||||||
|
echo "### requirements.txt" >> $GITHUB_STEP_SUMMARY
|
||||||
|
pip-audit -r requirements.txt --format markdown >> $GITHUB_STEP_SUMMARY 2>/dev/null || echo "No issues found" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check pyproject.toml if exists
|
||||||
|
if [ -f pyproject.toml ]; then
|
||||||
|
echo "### pyproject.toml" >> $GITHUB_STEP_SUMMARY
|
||||||
|
pip-audit --format markdown >> $GITHUB_STEP_SUMMARY 2>/dev/null || echo "No issues found" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Secret Scanning
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
secret-scan:
|
||||||
|
name: Secret Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install truffleHog
|
||||||
|
run: pip install trufflehog
|
||||||
|
|
||||||
|
- name: Scan for secrets
|
||||||
|
run: |
|
||||||
|
echo "## Secret Scan Results" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Scan with truffleHog
|
||||||
|
trufflehog filesystem . --only-verified --json 2>/dev/null | head -20 > secrets.json || true
|
||||||
|
|
||||||
|
if [ -s secrets.json ]; then
|
||||||
|
echo "::warning::Potential secrets detected. Review secrets.json"
|
||||||
|
echo "Potential secrets found - review required" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "No verified secrets detected" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Check for common secret patterns
|
||||||
|
run: |
|
||||||
|
echo "### Pattern Checks" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Check for AWS keys
|
||||||
|
if grep -rE "AKIA[0-9A-Z]{16}" --include="*.py" --include="*.sh" --include="*.yaml" . 2>/dev/null; then
|
||||||
|
echo "::warning::Potential AWS access key found"
|
||||||
|
echo "- Potential AWS key pattern detected" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for private keys
|
||||||
|
if grep -rE "BEGIN (RSA |DSA |EC |OPENSSH )?PRIVATE KEY" --include="*.py" --include="*.sh" --include="*.pem" . 2>/dev/null; then
|
||||||
|
echo "::warning::Private key found in repository"
|
||||||
|
echo "- Private key detected" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for hardcoded passwords
|
||||||
|
if grep -rEi "password\s*=\s*['\"][^'\"]{8,}['\"]" --include="*.py" --include="*.sh" . 2>/dev/null; then
|
||||||
|
echo "::warning::Potential hardcoded password found"
|
||||||
|
echo "- Potential hardcoded password detected" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Pattern scan complete" >> $GITHUB_STEP_SUMMARY
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# SAST (Static Application Security Testing)
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
sast:
|
||||||
|
name: SAST Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install Bandit
|
||||||
|
run: pip install bandit
|
||||||
|
|
||||||
|
- name: Run Bandit security scan
|
||||||
|
run: |
|
||||||
|
echo "## Bandit Security Scan" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
bandit -r . -f json -o bandit-report.json --exclude './.git,./node_modules,./.venv' || true
|
||||||
|
|
||||||
|
# Convert to markdown summary
|
||||||
|
if [ -f bandit-report.json ]; then
|
||||||
|
ISSUES=$(cat bandit-report.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d.get('results', [])))")
|
||||||
|
echo "Found $ISSUES security issues" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ "$ISSUES" -gt 0 ]; then
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Top Issues" >> $GITHUB_STEP_SUMMARY
|
||||||
|
cat bandit-report.json | python3 -c "
|
||||||
|
import json, sys
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
for r in d.get('results', [])[:10]:
|
||||||
|
print(f\"- **{r['issue_severity']}**: {r['issue_text']} ({r['filename']}:{r['line_number']})\")
|
||||||
|
" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Upload Bandit report
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: bandit-report
|
||||||
|
path: bandit-report.json
|
||||||
|
retention-days: 30
|
||||||
61
.github/workflows/stale.yml
vendored
Normal file
61
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Stale Issue/PR Management
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Automatically marks and closes stale issues and PRs.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Stale
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *' # Daily at midnight
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
name: Mark Stale Issues and PRs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v9
|
||||||
|
with:
|
||||||
|
# Issue configuration
|
||||||
|
stale-issue-message: |
|
||||||
|
This issue has been automatically marked as stale because it has not had recent activity.
|
||||||
|
It will be closed in 14 days if no further activity occurs.
|
||||||
|
|
||||||
|
If this issue is still relevant:
|
||||||
|
- Add a comment explaining the current status
|
||||||
|
- Remove the `stale` label
|
||||||
|
|
||||||
|
Thank you for your contributions to BlackRoad OS!
|
||||||
|
stale-issue-label: 'stale'
|
||||||
|
days-before-issue-stale: 60
|
||||||
|
days-before-issue-close: 14
|
||||||
|
exempt-issue-labels: 'pinned,security,critical,in-progress'
|
||||||
|
|
||||||
|
# PR configuration
|
||||||
|
stale-pr-message: |
|
||||||
|
This pull request has been automatically marked as stale because it has not had recent activity.
|
||||||
|
It will be closed in 7 days if no further activity occurs.
|
||||||
|
|
||||||
|
If this PR is still needed:
|
||||||
|
- Rebase on the latest main branch
|
||||||
|
- Address any review feedback
|
||||||
|
- Add a comment with status update
|
||||||
|
|
||||||
|
Thank you for your contributions!
|
||||||
|
stale-pr-label: 'stale'
|
||||||
|
days-before-pr-stale: 30
|
||||||
|
days-before-pr-close: 7
|
||||||
|
exempt-pr-labels: 'pinned,security,do-not-close'
|
||||||
|
|
||||||
|
# General
|
||||||
|
remove-stale-when-updated: true
|
||||||
|
operations-per-run: 100
|
||||||
72
.github/workflows/welcome.yml
vendored
Normal file
72
.github/workflows/welcome.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# BlackRoad OS - Welcome New Contributors
|
||||||
|
# Copyright (c) 2025 BlackRoad OS, Inc. / Alexa Louise Amundson
|
||||||
|
# All Rights Reserved.
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
|
# Welcomes first-time contributors with helpful information.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
name: Welcome
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
welcome:
|
||||||
|
name: Welcome New Contributors
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/first-interaction@v1
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
issue-message: |
|
||||||
|
Welcome to BlackRoad OS! 👋
|
||||||
|
|
||||||
|
Thank you for opening your first issue. We appreciate your contribution to making BlackRoad better.
|
||||||
|
|
||||||
|
**Quick links:**
|
||||||
|
- 📖 [Documentation](./docs/)
|
||||||
|
- 🏗️ [Architecture Overview](./docs/ARCHITECTURE_LEARNING_RANK.md)
|
||||||
|
- 💬 [Discussions](../../discussions)
|
||||||
|
|
||||||
|
**While you wait:**
|
||||||
|
- Make sure you've read the issue template completely
|
||||||
|
- Add any relevant labels if you can
|
||||||
|
- Feel free to ask questions if anything is unclear
|
||||||
|
|
||||||
|
A maintainer will review your issue soon. Thank you for your patience!
|
||||||
|
|
||||||
|
— *The BlackRoad OS Team* ✨
|
||||||
|
|
||||||
|
pr-message: |
|
||||||
|
Welcome to BlackRoad OS! 🎉
|
||||||
|
|
||||||
|
Thank you for opening your first pull request. We're excited to review your contribution!
|
||||||
|
|
||||||
|
**Before we review:**
|
||||||
|
- [ ] Ensure CI checks pass
|
||||||
|
- [ ] Add tests if applicable
|
||||||
|
- [ ] Update documentation if needed
|
||||||
|
- [ ] Ensure copyright headers are present
|
||||||
|
|
||||||
|
**Review process:**
|
||||||
|
1. A maintainer will review your PR
|
||||||
|
2. They may request changes or ask questions
|
||||||
|
3. Once approved, it will be merged
|
||||||
|
|
||||||
|
**Need help?**
|
||||||
|
- Check our [contribution guidelines](./CONTRIBUTING.md)
|
||||||
|
- Ask questions in the PR comments
|
||||||
|
- Join our discussions
|
||||||
|
|
||||||
|
Thank you for contributing to BlackRoad OS!
|
||||||
|
|
||||||
|
— *The BlackRoad OS Team* 🚀
|
||||||
Reference in New Issue
Block a user