diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4c06b9a3f..e573cde61 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -38,3 +38,12 @@ /CONTRIBUTING.md @YieldVault-RWA/docs-maintainers @YieldVault-RWA/core-maintainers /TRIAGE_AND_REVIEW.md @YieldVault-RWA/docs-maintainers @YieldVault-RWA/core-maintainers /README.md @YieldVault-RWA/docs-maintainers + +# Monitoring & Observability +/monitoring/ @YieldVault-RWA/devops-maintainers + +# Testing Infrastructure +/tests/ @YieldVault-RWA/backend-maintainers @YieldVault-RWA/frontend-maintainers + +# Packages +/packages/ @YieldVault-RWA/backend-maintainers diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f7c0010af..229a69156 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -22,8 +22,23 @@ Describe what should have happened. Describe what happened instead, including any errors, logs, or stack traces. ## 📍 Impact -- Affected area: `scope: frontend` / `scope: backend` / `scope: contracts` / `scope: infra` -- Severity / priority: `priority: p0-critical` / `priority: p1-high` / `priority: p2-medium` / `priority: p3-low` + +### Affected Package +Select the package(s) affected by this bug: +- [ ] `contracts` - Smart contracts & blockchain +- [ ] `backend` - Backend services & API +- [ ] `frontend` - UI & React components +- [ ] `docs` - Documentation +- [ ] `infra` - Infrastructure, CI/CD, deployment + +### Severity +Select the severity level based on impact: +- [ ] `critical` - Production outage, data loss, security breach +- [ ] `high` - Feature broken, significant performance degradation +- [ ] `medium` - Feature partially broken, user workflow impacted +- [ ] `low` - Minor bug, cosmetic issue, documentation + +### Environment - Environment: Local / Testnet / Mainnet - Browser / OS / Runtime: e.g. Chrome v120 / Windows / Node v20 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1968d8380..89101f02d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -52,6 +52,20 @@ updates: - "security" - "general" + - package-ecosystem: "npm" + directory: "/packages/api-schemas" + schedule: + interval: "weekly" + day: "monday" + time: "04:00" + open-pull-requests-limit: 10 + security-updates: true + rebase-strategy: auto + labels: + - "dependencies" + - "security" + - "general" + - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/.github/workflows/dependency-security.yml b/.github/workflows/dependency-security.yml index 18804cc58..662e42689 100644 --- a/.github/workflows/dependency-security.yml +++ b/.github/workflows/dependency-security.yml @@ -97,3 +97,36 @@ jobs: uses: actions/dependency-review-action@v4 with: fail-on-severity: high + + npm-license-check: + name: NPM License Check + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + + - name: Enable Corepack & Setup pnpm + run: | + corepack enable + corepack prepare pnpm@9.12.0 --activate + + - name: Install Dependencies + run: pnpm install --frozen-lockfile + + - name: Install license-checker + run: npm install -g license-checker-rseidelsohn + + - name: Check Frontend Licenses + working-directory: ./frontend + run: | + license-checker --onlyAllow "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;0BSD;CC0-1.0;Unlicense;Python-2.0;CC-BY-3.0;CC-BY-4.0" --summary + + - name: Check Backend Licenses + working-directory: ./backend + run: | + license-checker --onlyAllow "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;0BSD;CC0-1.0;Unlicense;Python-2.0;CC-BY-3.0;CC-BY-4.0" --summary diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index cc52ba50a..f9a5b80f2 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,3 +28,33 @@ jobs: run: | cargo doc -p share-price-math --no-deps cargo doc -p mock-strategy --no-deps + continue-on-error: false + + spell-check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install cspell + run: npm install -g cspell + + - name: Run spell check + run: cspell "**/*.md" --config cspell.json + + link-check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check links + uses: lycheeverse/lychee-action@v1 + with: + args: --verbose --no-progress --accept 200,403,429 --timeout 30 --max-retries 3 '**/*.md' + fail: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 884f67d37..49590461d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,7 +54,47 @@ jobs: branch: "chore/changelog-${{ github.ref_name }}" base: "main" - # Create the GitHub Release with the generated notes + # Build Rust workspace + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Build Rust workspace + run: cargo build --release --workspace + + # Build frontend + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + + - name: Enable Corepack + run: | + corepack enable + corepack prepare pnpm@9.12.0 --activate + + - name: Install frontend dependencies + working-directory: ./frontend + run: pnpm install --frozen-lockfile + + - name: Build frontend + working-directory: ./frontend + run: pnpm build + + # Generate SBOM for Rust workspace + - name: Install cargo-sbom + run: cargo install cargo-sbom + + - name: Generate Rust SBOM + run: cargo sbom --output-format spdx_json_2_3 > rust-sbom.spdx.json + + # Generate SBOM for frontend + - name: Generate Frontend SBOM + working-directory: ./frontend + run: | + npm install -g @cyclonedx/cyclonedx-npm + cyclonedx-npm --output-file ../frontend-sbom.json + + # Create the GitHub Release with the generated notes and SBOMs - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: @@ -63,3 +103,6 @@ jobs: body_path: /tmp/release-notes.md draft: false prerelease: ${{ contains(github.ref_name, '-') }} + files: | + rust-sbom.spdx.json + frontend-sbom.json diff --git a/README.md b/README.md index 0b9f98d79..2e739734f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This project is structured as a monorepo containing both the Stellar Soroban sma - `/contracts/vault/`: Contains the Rust Soroban smart contract for handling the vault logic, fractional share minting (`yvUSDC`), scaling withdrawals, and simulated yield accrual. - `/contracts/mock-strategy/`: Contains test mock contracts for the Korean sovereign debt strategy and price oracle. - `/frontend/`: Contains the React + Vite frontend application, integrating `@stellar/freighter-api` for seamless user wallet connections and a premium UI to interact with the protocol. -- `/docs/`: Contains the Product Requirements Document (PRD), Architecture Document, [Domain Glossary](./docs/GLOSSARY.md), [Vault Invariants](./docs/VAULT_INVARIANTS.md), [Protocol Risk Limits](./docs/PROTOCOL_RISK_LIMITS.md), [Oracle Failure Handling](./docs/ORACLE_FAILURE_HANDLING.md), [Performance Regression Thresholds](./docs/PERFORMANCE_REGRESSION.md), and tracked GitHub issues. See also the [Deposit & Withdrawal Lifecycle](./docs/DEPOSIT_WITHDRAWAL_LIFECYCLE.md) for sequence diagrams, the [Deposit & Withdrawal Troubleshooting Guide](./docs/DEPOSIT_WITHDRAWAL_TROUBLESHOOTING.md) for diagnosing failed operations, and the [Dependency Update Policy](./docs/DEPENDENCY_UPDATE_POLICY.md) for upgrade cadence, testing gates, CVE SLAs, and high-risk library requirements. +- `/docs/`: Contains the Product Requirements Document (PRD), Architecture Document, [Domain Glossary](./docs/GLOSSARY.md), [Vault Invariants](./docs/VAULT_INVARIANTS.md), [Protocol Risk Limits](./docs/PROTOCOL_RISK_LIMITS.md), [Oracle Failure Handling](./docs/ORACLE_FAILURE_HANDLING.md), [Performance Regression Thresholds](./docs/PERFORMANCE_REGRESSION.md), [Root Scripts Reference](./docs/ROOT_SCRIPTS_REFERENCE.md), and tracked GitHub issues. See also the [Deposit & Withdrawal Lifecycle](./docs/DEPOSIT_WITHDRAWAL_LIFECYCLE.md) for sequence diagrams, the [Deposit & Withdrawal Troubleshooting Guide](./docs/DEPOSIT_WITHDRAWAL_TROUBLESHOOTING.md) for diagnosing failed operations, and the [Dependency Update Policy](./docs/DEPENDENCY_UPDATE_POLICY.md) for upgrade cadence, testing gates, CVE SLAs, and high-risk library requirements. ## Architecture diff --git a/TRIAGE_LABELS.md b/TRIAGE_LABELS.md index b3cfc9fe9..ed794ed62 100644 --- a/TRIAGE_LABELS.md +++ b/TRIAGE_LABELS.md @@ -27,6 +27,7 @@ Severity indicates impact and urgency. Every issue must have exactly one severit | `high` | 🟠 Orange | Feature broken, significant performance degradation, security vulnerability (no active exploit) | 1 hour | 1 day | | `medium` | 🟡 Yellow | Feature partially broken, user workflow impacted, performance issue (non-critical path) | 4 hours | 3 days | | `low` | 🟢 Green | Minor bug, cosmetic issue, documentation, question | 1 day | 2 weeks | +| `trivial` | 🔵 Blue | Very minor fix, typo, extremely low priority | 3 days | 4 weeks | **Severity Definitions**: @@ -99,6 +100,7 @@ Status indicates where the issue is in its lifecycle. Use exactly one status lab | Label | Purpose | Example | |---|---|---| | `roadmap-qX-YYYY` | Links issue to roadmap phase | `roadmap-q3-2026`, `roadmap-q4-2026` | +| `stellar-wave` | Links issue to Stellar Wave initiative | Strategic work related to Stellar blockchain | | `breaking-change` | Requires major version bump | API signature change | | `security` | Security-related (in addition to `area:security`) | Use for visibility | | `good-first-issue` | Suitable for new contributors | Small scope, clear requirements | diff --git a/contracts/vault/src/lib.rs b/contracts/vault/src/lib.rs index 22e6d6983..eb0965347 100644 --- a/contracts/vault/src/lib.rs +++ b/contracts/vault/src/lib.rs @@ -388,7 +388,18 @@ pub struct StrategyProposal { #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] +#[contracttype] /// Pending large withdrawal with 24-hour timelock. +/// +/// ## Share Price Behavior +/// +/// The shares recorded here are NOT reserved or priced at request time. +/// When `execute_withdrawal` is called after the timelock expires, the shares +/// are converted to assets using the then-current `total_assets` and `total_shares`. +/// This means the user's effective share price depends on what happens during the +/// timelock period (yield accrual, deposits, other withdrawals, etc.). +/// +/// Related: issue #1683 pub struct PendingWithdrawal { pub shares: i128, pub unlock_timestamp: u64, @@ -4251,6 +4262,11 @@ impl YieldVault { if threshold <= 0 { return Err(VaultError::InvalidDaoThreshold); } + let total_assets: i128 = env.storage().instance().get(&DataKey::TotalAssets).unwrap_or(0); + let max_threshold = total_assets.saturating_mul(95).saturating_div(100); + if threshold > max_threshold { + return Err(VaultError::InvalidDaoThreshold); + } env.storage() .instance() .set(&DataKey::LargeWithdrawalThreshold, &threshold); @@ -4331,6 +4347,10 @@ impl YieldVault { let admin: Address = get_admin(&env).expect("Admin not set"); admin.require_auth(); Self::assert_admin_param_interval(&env)?; + const MAX_COOLDOWN: u64 = 365 * 24 * 60 * 60; + if seconds > MAX_COOLDOWN { + return Err(VaultError::InvalidDaoThreshold); + } let old: u64 = env .storage() .instance() diff --git a/cspell.json b/cspell.json new file mode 100644 index 000000000..43aea07b8 --- /dev/null +++ b/cspell.json @@ -0,0 +1,56 @@ +{ + "version": "0.2", + "language": "en-US", + "words": [ + "Soroban", + "Freighter", + "yvUSDC", + "USDC", + "XLM", + "Stellar", + "blockchain", + "smartcontract", + "smartcontracts", + "testnet", + "mainnet", + "keypair", + "keypairs", + "Junirezz", + "YieldVault", + "RWA", + "Rustc", + "Wasm", + "WASM", + "rustup", + "pnpm", + "typecheck", + "SBOM", + "SPDX", + "CycloneDX", + "lockfile", + "codeowners", + "repo", + "Github", + "deps", + "codeql", + "slither", + "gitleaks", + "clippy", + "rustfmt" + ], + "ignorePaths": [ + "node_modules", + "target", + "dist", + "build", + "*.lock", + "*.log", + "coverage", + ".git" + ], + "ignoreRegExpList": [ + "/0x[0-9a-fA-F]+/", + "/[A-Z0-9]{56}/", + "/G[A-Z0-9]{55}/" + ] +} diff --git a/docs/ROOT_SCRIPTS_REFERENCE.md b/docs/ROOT_SCRIPTS_REFERENCE.md new file mode 100644 index 000000000..db86dfed8 --- /dev/null +++ b/docs/ROOT_SCRIPTS_REFERENCE.md @@ -0,0 +1,199 @@ +# Root Package Scripts Reference + +This document lists all scripts in the root `package.json`, what they check or run, and when to use them. + +## Installation & Setup + +### `pnpm check:pnpm-version` +Verifies that the installed pnpm version matches the required version (≥9.12). +Run before install to ensure package manager compatibility. + +### `pnpm prepare` +Sets up Husky git hooks (commit-msg, pre-commit). +Runs automatically after `pnpm install`. + +## Build Scripts + +### `pnpm build:schemas` +Builds API schema packages used by backend and frontend. +Must run before building backend or frontend. + +### `pnpm build` +Full monorepo build: schemas → backend → frontend. +Use before production deployment or release. + +### `pnpm typecheck` +Type-checks all TypeScript packages without emitting files. +Use in CI or before committing to catch type errors. + +## Development Scripts + +### `pnpm dev` +Starts both backend and frontend in parallel using concurrently. +Use for full-stack local development. + +### `pnpm dev:backend` +Starts the backend development server with hot reload. +Builds schemas first, waits for database, then starts backend. + +### `pnpm dev:frontend` +Starts the frontend development server with hot module replacement. +Builds schemas first, then starts Vite dev server. + +### `pnpm wait-for-db` +Blocks until the database is ready. +Used internally by `dev:backend` to prevent startup failures. + +## Testing Scripts + +### `pnpm test` +Runs backend Jest tests with coverage, frontend Vitest tests, and root script tests. +Use in CI or before committing to ensure all tests pass. + +### `pnpm test:backend` +Runs only backend Jest tests with coverage in serial mode. + +### `pnpm test:frontend` +Runs only frontend Vitest tests in single-run mode (no watch). + +### `pnpm test:root` +Runs root-level script tests using Vitest. + +### `pnpm test:scripts` +Alias for `test:root`. + +### `pnpm test:all` +Runs all test suites: backend, frontend, and root scripts. +Use as final verification before pushing. + +### `pnpm test:flaky` +Runs only flaky backend tests to detect instability. + +### `pnpm test:flaky-detector` +Executes backend flaky test detection suite. + +### `pnpm test:wait-for-db` +Tests the database wait script functionality. + +## Validation Scripts + +### `pnpm validate` +Runs all validation scripts in sequence. Fails fast on first error. +Checks contribution standards, testing strategy, sprint/triage conventions, release notes, NFR baselines, CODEOWNERS, PR template, and Renovate config. +**Use before opening a PR or in CI to ensure policy compliance.** + +### `pnpm validate:frontend-env` +Validates frontend environment variables against required schema. +Checks `.env.example` and actual `.env` for completeness. + +### `pnpm validate:contribution-standards` +Ensures CONTRIBUTING.md matches enforced branch naming and PR conventions. + +### `pnpm validate:testing-strategy` +Verifies TESTING_STRATEGY.md covers unit, integration, and E2E guidance. + +### `pnpm validate:sprint-and-triage` +Checks sprint label formats and TRIAGE_LABELS.md taxonomy. + +### `pnpm validate:release-notes` +Validates release notes template and conventional commit configuration. + +### `pnpm validate:nfr-baselines` +Ensures NFR baselines (SLO, RTO, RPO) are documented and meet thresholds. + +### `pnpm validate:incident-severity` +Checks incident severity definitions and escalation matrix. + +### `pnpm validate:codeowners` +Verifies CODEOWNERS covers every top-level directory and all handles are valid. + +### `pnpm validate:pr-template` +Ensures PR template includes all required sections. + +### `pnpm validate:renovate` +Validates Renovate configuration for dependency automation. + +## License & Compliance + +### `pnpm validate:licenses` +Scans dependencies for license compliance violations. +Fails on GPL/AGPL or other restrictive licenses. + +### `pnpm check:licenses` +Runs license validation and its test suite. + +## Image & Asset Optimization + +### `pnpm compress:images` +Compresses PNG images in the repo to reduce size. +Run before committing large image assets. + +### `pnpm validate:images` +Checks image file sizes against maximum thresholds. + +### `pnpm validate:line-endings` +Ensures generated artifacts have consistent line endings (LF). + +## Security & Auditing + +### `pnpm audit:pnpm` +Runs pnpm audit with high-severity threshold. +Fails on high or critical vulnerabilities. + +### `pnpm check:security-audit` +Runs Renovate validation, tests, and pnpm audit. +Use before releases to catch security issues. + +## Linting & Formatting + +### `pnpm lint:staged` +Runs lint-staged on staged files (enforced by Husky pre-commit hook). + +### `pnpm commitlint` +Validates commit messages against conventional commit format. +Enforced by Husky commit-msg hook. + +## Test Coverage Scripts + +### `pnpm test:validate-frontend-env` +Tests the frontend environment validator using Vitest. + +### `pnpm test:validate-workspace-test-scripts` +Verifies workspace test scripts are correctly configured. + +### `pnpm test:validate-codeowners` +Tests CODEOWNERS validation logic. + +### `pnpm check:codeowners` +Runs CODEOWNERS validation and its tests. + +### `pnpm test:validate-pr-template` +Tests PR template validation. + +### `pnpm check:pr-template` +Runs PR template validation and its tests. + +### `pnpm test:validate-renovate` +Tests Renovate configuration validation. + +### `pnpm test:validate-licenses` +Tests license validation logic. + +### `pnpm test:validate-images` +Tests image size validation. + +### `pnpm test:validate-line-endings` +Tests line ending validation for generated artifacts. + +## When to Run What + +| Scenario | Command | Frequency | +|----------|---------|-----------| +| Starting work | `pnpm install` → `pnpm dev` | Once per session | +| Before committing | `pnpm test:all` → `pnpm validate` | Every commit | +| Before opening PR | `pnpm build` → `pnpm test:all` → `pnpm validate` | Every PR | +| After dependency update | `pnpm check:licenses` → `pnpm check:security-audit` | After `pnpm add` | +| Before release | `pnpm build` → `pnpm test:all` → `pnpm validate` → `pnpm check:security-audit` | Every release | +| CI pipeline | `pnpm install` → `pnpm build` → `pnpm test:all` → `pnpm validate` | Every push | +| Debugging flaky tests | `pnpm test:flaky-detector` | As needed | +| After adding images | `pnpm compress:images` → `pnpm validate:images` | Before commit | diff --git a/package.json b/package.json index de4e044dc..1b9f719d5 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,8 @@ "validate:renovate": "tsx scripts/validate-renovate-config.ts", "test:validate-renovate": "vitest run scripts/validate-renovate-config.test.ts", "audit:pnpm": "pnpm audit --audit-level=high", - "check:security-audit": "pnpm validate:renovate && pnpm test:validate-renovate && pnpm audit --audit-level=high" + "check:security-audit": "pnpm validate:renovate && pnpm test:validate-renovate && pnpm audit --audit-level=high", + "validate": "pnpm validate:contribution-standards && pnpm validate:testing-strategy && pnpm validate:sprint-and-triage && pnpm validate:release-notes && pnpm validate:nfr-baselines && pnpm validate:codeowners && pnpm validate:pr-template && pnpm validate:renovate" }, "pnpm": { "overrides": {