diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 44724aa23..a2ad4797d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,27 @@ # Default owners for everything +# NOTE: Verify that all handles below are members of the rocketride-org organization. +# GitHub usernames confirmed to exist: @jmaionchi, @Rod-Christensen, @stepmikhaylov, @kwit75 +# Org membership could not be verified programmatically (requires admin access). * @jmaionchi @Rod-Christensen @stepmikhaylov # DevOps maintainers /.github/ @kwit75 + +# C++ engine — requires engine team review +packages/server/ @jmaionchi @Rod-Christensen + +# Python nodes — requires ML team review +nodes/ @stepmikhaylov @jmaionchi + +# Client SDKs +packages/client-typescript/ @jmaionchi @stepmikhaylov +packages/client-python/ @jmaionchi @stepmikhaylov +packages/client-mcp/ @jmaionchi @stepmikhaylov + +# CI/CD — requires DevOps review (/.github/ covered by DevOps maintainers rule above) +docker/ @kwit75 + +# Security-sensitive files +packages/ai/src/ai/web/middleware.py @jmaionchi @Rod-Christensen +packages/ai/src/ai/account/ @jmaionchi @Rod-Christensen +SECURITY.md @jmaionchi @Rod-Christensen diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 000000000..2a565507d --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,59 @@ +name: Code Coverage + +on: + pull_request: + push: + branches: [develop, main] + +permissions: + contents: read + +jobs: + coverage: + name: Python coverage + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-cov + # Install node dependencies if requirements exist + if [ -f nodes/requirements.txt ]; then pip install -r nodes/requirements.txt; fi + if [ -f packages/ai/requirements.txt ]; then pip install -r packages/ai/requirements.txt; fi + # Install packages in editable mode for coverage tracking + if [ -f nodes/setup.py ] || [ -f nodes/pyproject.toml ]; then pip install -e nodes/; fi + if [ -f packages/ai/setup.py ] || [ -f packages/ai/pyproject.toml ]; then pip install -e packages/ai/; fi + + - name: Run tests with coverage + id: tests + continue-on-error: true + run: | + pytest \ + --cov=nodes \ + --cov=packages \ + --cov-report=xml:coverage.xml \ + --cov-report=term-missing \ + --junitxml=junit.xml \ + -q \ + nodes/test/ test/ + + - name: Upload coverage to Codecov + if: always() + uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4 + with: + files: coverage.xml + fail_ci_if_error: false + flags: python + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Fail if tests failed + if: steps.tests.outcome == 'failure' + run: exit 1 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 000000000..90c6b53e1 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,22 @@ +name: Dependency Review + +on: [pull_request] + +permissions: + contents: read + pull-requests: write + +jobs: + dependency-review: + name: Review dependencies + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Dependency Review + uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 + with: + fail-on-severity: high + deny-licenses: GPL-2.0-only, GPL-2.0-or-later, GPL-3.0-only, GPL-3.0-or-later, AGPL-3.0-only, AGPL-3.0-or-later + comment-summary-in-pr: always diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml new file mode 100644 index 000000000..c0c936d55 --- /dev/null +++ b/.github/workflows/gitleaks.yml @@ -0,0 +1,24 @@ +name: Secrets Scanning + +on: + pull_request: + push: + branches: [develop, main] + +permissions: + contents: read + +jobs: + gitleaks: + name: Detect secrets + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + fetch-depth: 0 + + - name: Run Gitleaks + uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2.3.9 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitleaks.toml b/.gitleaks.toml index d9aa81cb0..17ce9f3de 100644 --- a/.gitleaks.toml +++ b/.gitleaks.toml @@ -19,6 +19,10 @@ paths = ['''\.pipe$'''] '''\$[A-Z_]+''', '''\$\{[A-Z_]+\}''', ] + paths = [ + '''testdata/''', + '''test/fixtures/''', + ] # Custom rule: detect hardcoded keys in services.json node configs [[rules]] @@ -34,16 +38,7 @@ paths = ['''services.*\.json$'''] '''\$[A-Z_]+''', '''\$\{[A-Z_]+\}''', ] - -# Global allowlist — skip lock files, build output, test fixtures -[allowlist] -paths = [ - '''pnpm-lock\.yaml''', - '''package-lock\.json''', - '''\.gitleaks\.toml''', - '''build/''', - '''dist/''', - '''downloads/''', - '''node_modules/''', - '''\.claude/''', -] + paths = [ + '''testdata/''', + '''test/fixtures/''', + ] diff --git a/apps/chat-ui/package.json b/apps/chat-ui/package.json index e3ebd1280..2cedea233 100644 --- a/apps/chat-ui/package.json +++ b/apps/chat-ui/package.json @@ -41,3 +41,4 @@ "typescript": "^5.2.2" } } + diff --git a/apps/chat-ui/pnpm-lock.yaml b/apps/chat-ui/pnpm-lock.yaml index 9b60ae178..fe74cedb0 100644 --- a/apps/chat-ui/pnpm-lock.yaml +++ b/apps/chat-ui/pnpm-lock.yaml @@ -7,3 +7,4 @@ settings: importers: .: {} + diff --git a/apps/dropper-ui/package.json b/apps/dropper-ui/package.json index f43221eeb..e7c49d04e 100644 --- a/apps/dropper-ui/package.json +++ b/apps/dropper-ui/package.json @@ -40,3 +40,4 @@ "typescript": "^5.2.2" } } + diff --git a/apps/dropper-ui/pnpm-lock.yaml b/apps/dropper-ui/pnpm-lock.yaml index 9b60ae178..fe74cedb0 100644 --- a/apps/dropper-ui/pnpm-lock.yaml +++ b/apps/dropper-ui/pnpm-lock.yaml @@ -7,3 +7,4 @@ settings: importers: .: {} + diff --git a/apps/vscode/package.json b/apps/vscode/package.json index 06366c79f..8c42a3a93 100644 --- a/apps/vscode/package.json +++ b/apps/vscode/package.json @@ -440,3 +440,4 @@ "dist/**" ] } + diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..ce81d70d1 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,20 @@ +coverage: + status: + project: + default: + target: auto + threshold: 2% + patch: + default: + target: 80% + ignore: + - "testdata/**" + - "docs/**" + - "scripts/**" + - "**/test_*.py" + - "**/conftest.py" + +comment: + layout: "reach,diff,flags,files" + behavior: default + require_changes: true diff --git a/docs/BRANCH_PROTECTION.md b/docs/BRANCH_PROTECTION.md new file mode 100644 index 000000000..3cb8e929b --- /dev/null +++ b/docs/BRANCH_PROTECTION.md @@ -0,0 +1,78 @@ +# Branch Protection Rules + +Recommended branch protection configuration for the RocketRide Server repository. + +## `develop` Branch (Primary Integration Branch) + +### Required Settings + +| Setting | Value | Rationale | +|---------|-------|-----------| +| Require pull request reviews | Yes | All changes must be peer-reviewed | +| Required approving reviews | 1 | Minimum one approval before merge | +| Dismiss stale reviews on new pushes | Yes | Force re-review after changes | +| Require review from CODEOWNERS | Yes | Enforces team-based ownership (see `.github/CODEOWNERS`) | +| Require status checks to pass | Yes | Prevents merging broken code | +| Require branches to be up to date | Yes | Ensures CI runs against latest develop | +| Require linear history | Yes | Keeps history clean (squash or rebase merges only) | +| Require signed commits | No | Optional; not all contributors have GPG keys configured | +| Include administrators | Yes | Rules apply to everyone, including admins | +| Restrict who can push | Yes | Only merge via PR; no direct pushes | +| Allow force pushes | No | Never allow force pushes to develop | +| Allow deletions | No | Prevent accidental branch deletion | + +### Required Status Checks + +These checks must pass before a PR can merge to `develop`: + +- `CI OK` (from `ci.yml` — the gatekeeper job that aggregates all CI results) +- `Detect secrets` (from `gitleaks.yml`) +- `Review dependencies` (from `dependency-review.yml`) +- `Validate PR title` (from `pr-checks.yml`) + +### Optional but Recommended Status Checks + +- `Python coverage` (from `coverage.yml` — advisory, not blocking) + +## `main` Branch (Production) + +Apply the same settings as `develop`, with these additions: + +| Setting | Value | Rationale | +|---------|-------|-----------| +| Required approving reviews | 2 | Higher bar for production releases | +| Restrict pushes to specific teams | DevOps only | Only release managers can merge to main | + +## How to Configure in GitHub UI + +1. Go to **Settings** > **Branches** > **Add branch protection rule** +2. Enter the branch name pattern (e.g., `develop`) +3. Enable each setting from the tables above +4. Under **Require status checks to pass before merging**: + - Search for and add each required check by name + - Enable **Require branches to be up to date before merging** +5. Click **Create** (or **Save changes** if editing) + +### Using GitHub CLI + +You can also configure branch protection via `gh`: + +```bash +gh api repos/{owner}/{repo}/branches/develop/protection \ + --method PUT \ + --field required_status_checks='{"strict":true,"contexts":["CI OK","Detect secrets","Review dependencies","Validate PR title"]}' \ + --field enforce_admins=true \ + --field required_pull_request_reviews='{"required_approving_review_count":1,"dismiss_stale_reviews":true,"require_code_owner_reviews":true}' \ + --field restrictions=null \ + --field required_linear_history=true \ + --field allow_force_pushes=false \ + --field allow_deletions=false +``` + +## Rulesets (GitHub Rulesets Alternative) + +GitHub Rulesets provide a newer, more flexible alternative to branch protection rules. +They support targeting multiple branches, bypass lists, and organization-level policies. + +To use rulesets instead, go to **Settings** > **Rules** > **Rulesets** > **New ruleset**. +The same settings from the tables above apply; rulesets simply offer a more granular UI. diff --git a/package.json b/package.json index 4f6790adf..3f532f3d3 100644 --- a/package.json +++ b/package.json @@ -93,3 +93,4 @@ "typescript-eslint": "^8.15.0" } } + diff --git a/packages/client-mcp/pyproject.toml b/packages/client-mcp/pyproject.toml index ac2fae72b..e2c53fea3 100644 --- a/packages/client-mcp/pyproject.toml +++ b/packages/client-mcp/pyproject.toml @@ -47,3 +47,4 @@ include = ["rocketride_mcp*"] [tool.setuptools.package-data] rocketride_mcp = ["pipelines/*.json"] + diff --git a/packages/client-python/pyproject.toml b/packages/client-python/pyproject.toml index 2b21429c1..a0b26c9d5 100644 --- a/packages/client-python/pyproject.toml +++ b/packages/client-python/pyproject.toml @@ -76,3 +76,4 @@ include = ["rocketride*"] [tool.setuptools.package-data] rocketride = ["py.typed"] + diff --git a/packages/client-typescript/package.json b/packages/client-typescript/package.json index a3138d52b..0e8f6634a 100644 --- a/packages/client-typescript/package.json +++ b/packages/client-typescript/package.json @@ -59,3 +59,4 @@ "ws": "^8.18.3" } } + diff --git a/packages/client-typescript/pnpm-lock.yaml b/packages/client-typescript/pnpm-lock.yaml index d43316972..0b53ea824 100644 --- a/packages/client-typescript/pnpm-lock.yaml +++ b/packages/client-typescript/pnpm-lock.yaml @@ -3877,3 +3877,4 @@ snapshots: yargs-parser: 21.1.1 yocto-queue@0.1.0: {} + diff --git a/packages/server/vcpkg.json b/packages/server/vcpkg.json index b74be2e05..40ff42230 100644 --- a/packages/server/vcpkg.json +++ b/packages/server/vcpkg.json @@ -39,3 +39,4 @@ "zstd" ] } + diff --git a/packages/shared-ui/package.json b/packages/shared-ui/package.json index 966ef1412..8e0fed9e3 100644 --- a/packages/shared-ui/package.json +++ b/packages/shared-ui/package.json @@ -112,3 +112,4 @@ "lucide-react": "^0.540.0" } } + diff --git a/packages/shared-ui/pnpm-lock.yaml b/packages/shared-ui/pnpm-lock.yaml index 569238c49..2e346cac5 100644 --- a/packages/shared-ui/pnpm-lock.yaml +++ b/packages/shared-ui/pnpm-lock.yaml @@ -9910,3 +9910,4 @@ snapshots: '@types/react': 18.2.79 immer: 9.0.21 react: 18.3.1 + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e8546bb85..58c337e27 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18218,3 +18218,4 @@ snapshots: react: 18.3.1 zwitch@2.0.4: {} + diff --git a/pyproject.toml b/pyproject.toml index 744471777..89ec51563 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,3 +86,4 @@ markers = [ "integration: marks tests as integration tests", ] asyncio_mode = "auto" +