Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# NOTE: Baseline coverage is ~29% (27.85% on develop as of 2026-Q2).
# The project/patch range [60%, 80%] below is aspirational for Phase 3
# coverage push (post-fast-check + property tests + Vitest utility tests).
# CI's ci.yml intentionally runs with "no thresholds, no gates", so this
# file does NOT currently block PRs — it only affects Codecov status
# badges. Update the range after Phase 2 coverage lands.
codecov:
notify:
wait_for_ci: true
require_ci_to_pass: true
comment:
behavior: default
layout: reach,diff,flags,tree
show_carryforward_flags: false
coverage:
precision: 2
range:
- 60.0
- 80.0
round: down
status:
changes: false
default_rules:
flag_coverage_not_uploaded_behavior: include
patch: true
project: true
slack_app: true
32 changes: 32 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.rs]
indent_size = 4

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2

# Makefiles require tabs (syntax)
[Makefile]
indent_style = tab

# Nix files: prettier handles formatting, allow 2-space indent
[*.nix]
indent_style = space
indent_size = 2

# JSON files: Prettier handles formatting with 2-space indent
[*.json]
indent_style = space
indent_size = 2
17 changes: 17 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Security-sensitive routes — require review
# Auth: webauthn, passkey, MFA, OIDC, TOTP
/server/server/api/v1/auth/ @BillyOutlast
/server/server/internal/auth/ @BillyOutlast

# Metadata providers — external HTTP integration, complex fallthrough
/server/server/internal/metadata/ @BillyOutlast

# Nitro server core (server/ dir)
/server/server/ @BillyOutlast

# Build, deps, CI
/server/.env.example @BillyOutlast
/.github/workflows/ @BillyOutlast
/AGENTS.md @BillyOutlast
/CLAUDE.md @BillyOutlast
/CONTRIBUTING.md @BillyOutlast
154 changes: 154 additions & 0 deletions .github/actions/rust-ci/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: Rust CI
description: >
Reusable Rust CI steps for Drop monorepo workspaces.
Handles checkout, toolchain, cache, system deps, fmt, clippy/check,
tests, coverage (llvm-cov + Codecov), and advisory cargo-audit.

inputs:
working-directory:
required: true
description: >
Working directory for cargo commands.
Example: libraries/droplet, cli, desktop/src-tauri

cache-workspaces:
required: true
description: >
Workspace mapping for swatinem/rust-cache.
Example: "./libraries/droplet -> target"

system-dependencies:
required: false
description: >
Shell commands to install system dependencies (apt-get etc.).
Omit or leave empty when no system deps are needed.
default: ""

lint-command:
required: true
description: >
Cargo lint/build command.
Example: cargo clippy --all-targets --all-features -- -D warnings

coverage-path:
required: true
description: >
Path to coverage.lcov relative to repo root (for Codecov upload).
Example: libraries/droplet/coverage.lcov

test-command:
required: false
description: Cargo test command.
default: cargo test --all-features --all --verbose

test-continue-on-error:
required: false
description: Whether to continue on test failure.
default: "false"

lint-continue-on-error:
required: false
description: Whether to continue on lint failure.
default: "false"

components:
required: false
description: Rust toolchain components (comma-separated).
default: rustfmt, clippy

runs:
using: composite
steps:
# ── Setup ──────────────────────────────────────────────────────
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@4fd1da8b0805d2d2e936788875a7d65dbd677dc2
with:
toolchain: nightly
components: ${{ inputs.components }}

- name: Rust cache
# pinned to v2
uses: swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae
with:
workspaces: ${{ inputs.cache-workspaces }}

# ── System dependencies ────────────────────────────────────────
- name: Install system dependencies
if: ${{ inputs.system-dependencies != '' }}
shell: bash
run: ${{ inputs.system-dependencies }}

# ── Format ─────────────────────────────────────────────────────
- name: Check formatting
shell: bash
working-directory: ${{ inputs.working-directory }}
run: cargo fmt --all -- --check

# ── Lint / Build ───────────────────────────────────────────────
- name: Lint / Build
shell: bash
working-directory: ${{ inputs.working-directory }}
continue-on-error: ${{ inputs.lint-continue-on-error == 'true' }}
run: ${{ inputs.lint-command }}

# ── Test ───────────────────────────────────────────────────────
- name: Run tests
shell: bash
working-directory: ${{ inputs.working-directory }}
continue-on-error: ${{ inputs.test-continue-on-error == 'true' }}
run: ${{ inputs.test-command }}

# ── Coverage ───────────────────────────────────────────────────
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov

- name: Generate code coverage
# Was continue-on-error: true — switched to false so coverage
# failures surface in CI. Codecov upload below still uses
# fail_ci_if_error: false, so generation failure is visible
# but won't block the pipeline.
continue-on-error: false
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
cargo llvm-cov --all-features --workspace \
--codecov --output-path coverage.lcov

- name: Upload coverage to Codecov
# pinned to v5
uses: codecov/codecov-action@04b047e8bb82a0c002c8312c1c880fbc6a999d45
with:
files: ${{ inputs.coverage-path }}
fail_ci_if_error: false

# ── Security audit ─────────────────────────────────────────────
- name: Install cargo-audit
uses: taiki-e/install-action@cargo-audit

- name: Audit dependencies
# cargo audit exits 1 on ANY advisory. Keep non-blocking here; the
# follow-up step fails only when a NEW (un-ignored) advisory is found
# that is not already documented in security/risk-register.yaml.
continue-on-error: true
shell: bash
working-directory: ${{ inputs.working-directory }}
run: cargo audit --json > /tmp/cargo-audit.json 2>/dev/null || true

- name: Check for new Rust advisories
# Run on success or failure of the audit step, but not on cancel.
# Use --min-severity high for cargo to catch DoS-class advisories
# (RUSTSEC-2026-0194/0195 in quick-xml are severity "high"); the
# script handles missing/empty/malformed JSON and missing risk
# register gracefully (exits 0 with a warning in both cases).
# Resolve the script via $GITHUB_WORKSPACE because this composite
# action is invoked with working-directory set to a sub-crate
# (cli/, desktop/src-tauri/, libraries/droplet/), where a relative
# `scripts/check-new-vulns.cjs` would not exist.
if: success() || failure()
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
node "$GITHUB_WORKSPACE/scripts/check-new-vulns.cjs" \
--format cargo \
--json /tmp/cargo-audit.json \
--min-severity high
158 changes: 158 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
version: 2

registries:
# Allow Dependabot to resolve private/skipped registry hosts from lockfiles
# (e.g. buf schema registry, GitHub Packages). Public registries need no entry.
npm-pkg-github:
type: "npm-registry"
url: "https://npm.pkg.github.com"
token: "${{secrets.GITHUB_TOKEN}}"

updates:
# ----- Node / pnpm workspace (root, server, sites/*, desktop) -----
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
time: "06:00"
timezone: "America/New_York"
open-pull-requests-limit: 10
groups:
# Patch + minor bumps bundled together to avoid PR spam
node-minor:
update-types: ["minor", "patch"]
# Pin major bumps separately for explicit review
node-major:
update-types: ["major"]
commit-message:
prefix: "deps"
prefix-development: "chore(deps-dev)"
labels: ["dependencies", "javascript"]
reviewers: ["BillyOutlast"]
# Keep lockfile in sync; pnpm-workspace.yaml declares onlyBuiltDependencies
# — keep Dependabot from re-enabling builds that the workspace intentionally skips.
rebase-strategy: "auto"

# ----- Nuxt 4 desktop app (separate pnpm workspace) -----
# desktop/main/ has its own pnpm-workspace.yaml and pnpm-lock.yaml,
# so root npm entry at "/" does not cover it. Scanned independently.
- package-ecosystem: "npm"
directory: "/desktop/main"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "America/New_York"
open-pull-requests-limit: 5
groups:
desktop-minor:
update-types: ["minor", "patch"]
desktop-major:
update-types: ["major"]
commit-message:
prefix: "deps(desktop)"
labels: ["dependencies", "javascript"]
rebase-strategy: "auto"

# ----- Rust workspace: CLI -----
- package-ecosystem: "cargo"
directory: "/cli"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "America/New_York"
open-pull-requests-limit: 5
groups:
rust-minor:
update-types: ["minor", "patch"]
rust-major:
update-types: ["major"]
commit-message:
prefix: "deps(cli)"
labels: ["dependencies", "rust"]

# ----- Rust workspace: droplet library -----
- package-ecosystem: "cargo"
directory: "/libraries/droplet"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "America/New_York"
open-pull-requests-limit: 5
groups:
rust-minor:
update-types: ["minor", "patch"]
rust-major:
update-types: ["major"]
commit-message:
prefix: "deps(droplet)"
labels: ["dependencies", "rust"]

# ----- Rust workspace: native_model library -----
- package-ecosystem: "cargo"
directory: "/libraries/native_model"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "America/New_York"
open-pull-requests-limit: 5
groups:
rust-minor:
update-types: ["minor", "patch"]
rust-major:
update-types: ["major"]
commit-message:
prefix: "deps(native_model)"
labels: ["dependencies", "rust"]

# ----- Rust workspace: desktop (Tauri) -----
- package-ecosystem: "cargo"
directory: "/desktop/src-tauri"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "America/New_York"
open-pull-requests-limit: 5
groups:
rust-minor:
update-types: ["minor", "patch"]
rust-major:
update-types: ["major"]
commit-message:
prefix: "deps(desktop)"
labels: ["dependencies", "rust"]

# ----- Dockerfile (root image) -----
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "America/New_York"
open-pull-requests-limit: 5
commit-message:
prefix: "deps(docker)"
labels: ["dependencies", "docker"]

# ----- GitHub Actions -----
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "America/New_York"
open-pull-requests-limit: 10
groups:
actions-minor:
update-types: ["minor", "patch"]
actions-major:
update-types: ["major"]
commit-message:
prefix: "deps(ci)"
labels: ["dependencies", "github-actions"]
Loading
Loading