diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..451722f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,99 @@ +name: Test and Build + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.12.0' + + # Frontend Linting + - name: Install frontend dependencies + working-directory: packages/demo-app-frontend + run: npm ci + + - name: Run ESLint (Frontend) + working-directory: packages/demo-app-frontend + run: npm run lint + + - name: Check Prettier formatting (Frontend) + working-directory: packages/demo-app-frontend + run: npx prettier --check . + + # Solidity Linting + - name: Install contract dependencies + working-directory: packages/trust-anchor-did-ethr + run: npm ci + + - name: Run Solhint (Contracts) + working-directory: packages/trust-anchor-did-ethr + run: npx solhint 'contracts/**/*.sol' + + test: + name: Test + needs: lint + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.12.0' + cache: 'npm' + cache-dependency-path: packages/trust-anchor-did-ethr/package-lock.json + + - name: Install dependencies + working-directory: packages/trust-anchor-did-ethr + run: npm ci + + - name: Run Hardhat tests + working-directory: packages/trust-anchor-did-ethr + run: npx hardhat test + + build: + name: Build + needs: test + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.12.0' + + # Compile Contracts + - name: Install contract dependencies + working-directory: packages/trust-anchor-did-ethr + run: npm ci + + - name: Compile smart contracts + working-directory: packages/trust-anchor-did-ethr + run: npx hardhat compile + + # Build Frontend + - name: Install frontend dependencies + working-directory: packages/demo-app-frontend + run: npm ci + + - name: Build frontend + working-directory: packages/demo-app-frontend + run: npm run build diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..236fe30 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +cd packages/demo-app-frontend && npx lint-staged diff --git a/BUILD.md b/BUILD.md index b63fd9a..960aa85 100644 --- a/BUILD.md +++ b/BUILD.md @@ -7,6 +7,7 @@ - [Installation](#installation) - [Running the Project](#running-the-project) - [Testing](#testing) +- [Development Workflow](#development-workflow) - [TypeScript Configuration](#typescript-configuration) - [Platform-Specific Notes](#platform-specific-notes) - [Deployment](#deployment) @@ -66,6 +67,14 @@ This project uses the following key dependencies: ## Installation +### Install Root Dependencies + +First, install root dependencies (required for Husky pre-commit hooks): + +```bash +npm install +``` + ### Install Dependencies for Each Package #### 1. Smart Contracts (trust-anchor-did-ethr) @@ -187,6 +196,45 @@ cd packages/demo-app-frontend npm run lint ``` +## Development Workflow + +### Pre-commit Hooks + +This project uses [Husky](https://typicode.github.io/husky/) and [lint-staged](https://github.com/okonet/lint-staged) to automatically lint your code before commits: + +**What happens when you commit:** +1. You stage files: `git add src/components/MyComponent.tsx` +2. You commit: `git commit -m "fix: update component"` +3. Pre-commit hook runs automatically: + - ESLint checks code quality and fixes issues + - Prettier formats code (indentation, spacing, etc.) + - Both tools auto-fix and re-stage files + - Unfixable errors block the commit +4. If successful, commit proceeds with clean, formatted code + +**Manual formatting:** +```bash +npm run format # Format all files with Prettier +npm run lint # Check code quality with ESLint +``` + +**Configuration:** +- Hook script: `.husky/pre-commit` +- Prettier rules: `packages/demo-app-frontend/.prettierrc` +- ESLint rules: `packages/demo-app-frontend/eslint.config.js` +- Staged file rules: `packages/demo-app-frontend/package.json` → `lint-staged` section + +### Continuous Integration (GitHub Actions) + +Pull requests and pushes to `main` trigger automated checks (`.github/workflows/ci.yml`): + +**CI Jobs:** +1. **Frontend Linting**: Runs ESLint on entire frontend codebase +2. **Frontend Formatting**: Checks Prettier formatting compliance +3. **Contract Validation**: Compiles smart contracts and runs full test suite + +**All checks must pass before merging.** The CI uses Node.js 22.12.0 to match local development. + ## TypeScript Configuration ### Smart Contracts (trust-anchor-did-ethr) diff --git a/CI_CD.md b/CI_CD.md new file mode 100644 index 0000000..78bb813 --- /dev/null +++ b/CI_CD.md @@ -0,0 +1,231 @@ +# CI/CD Pipeline Documentation + +This document describes the CI/CD pipeline for the On-Chain SSI project. + + +## Pipeline Structure + +The pipeline consists of three sequential stages: + +``` +Lint -> Test -> Build +``` + +Each stage must pass before the next stage runs. If any stage fails, the pipeline stops. + +### Workflow File + +Location: `.github/workflows/ci.yml` + +Triggers: +- On pull requests to `main` branch +- On pushes to `main` branch + +## Pipeline Stages + +### 1. Lint Stage + +**Purpose:** Validate code style and formatting + +**Checks:** +- **ESLint** - TypeScript/React code quality (frontend) +- **Prettier** - Code formatting consistency (frontend) +- **Solhint** - Solidity contract linting (contracts) + +**Configuration Files:** +- `packages/demo-app-frontend/eslint.config.js` - ESLint rules +- `packages/demo-app-frontend/.prettierrc` - Prettier formatting rules +- `packages/trust-anchor-did-ethr/.solhint.json` - Solhint rules (relaxed for practicality, it is work in progress to make them stricter) + +**Exit Criteria:** All linters pass with 0 errors + +### 2. Test Stage + +**Purpose:** Verify contract functionality + +**Requires:** Lint stage must pass + +**Tests:** +- Hardhat test suite (36 tests) +- Unit tests for all smart contracts +- Integration tests for DID workflows + +**Exit Criteria:** All tests pass + +### 3. Build Stage + +**Purpose:** Verify project can be compiled and built + +**Requires:** Test stage must pass + +**Builds:** +- Smart contract compilation (`npx hardhat compile`) +- Frontend production build (`npm run build`) + +**Exit Criteria:** Both contracts and frontend build successfully + +## Running Pipeline Stages Locally + +### Lint + +```bash +# Frontend +cd packages/demo-app-frontend +npm run lint +npx prettier --check . + +# Contracts +cd packages/trust-anchor-did-ethr +npx solhint 'contracts/**/*.sol' +``` + +### Test + +```bash +cd packages/trust-anchor-did-ethr +npx hardhat test +``` + +### Build + +```bash +# Contracts +cd packages/trust-anchor-did-ethr +npx hardhat compile + +# Frontend +cd packages/demo-app-frontend +npm run build +``` + +## Pre-commit Hooks + +The project uses [Husky](https://typicode.github.io/husky/) to enforce code quality before commits. + +**What runs on commit:** +1. ESLint checks staged TypeScript files +2. Prettier formats staged files +3. Changes are auto-fixed and staged again if possible +4. Commit is blocked if unfixable errors exist + +**Configuration:** +- `.husky/pre-commit` - Hook script +- `packages/demo-app-frontend/package.json` → `lint-staged` section + +**Bypass (emergency only):** +```bash +git commit --no-verify +``` + +## Expected Outputs + +### Successful Pipeline + +All three jobs show green checkmarks: +- Lint: All linters pass +- Test: All 36 tests pass +- Build: Contracts compile, frontend builds + +### Failed Pipeline + +Pipeline stops at the first failure: +- Lint fails: Test and Build stages do not run +- Test fails: Build stage does not run +- Build fails: PR cannot be merged + +## Troubleshooting + +### Linting Errors + +**ESLint fails:** +```bash +cd packages/demo-app-frontend +npm run lint +# Fix errors shown, or autofix: +npx eslint . --fix +``` + +**Prettier fails:** +```bash +cd packages/demo-app-frontend +npx prettier --check . # See what needs formatting +npm run format # Autoformat all files +``` + +**Solhint fails:** +```bash +cd packages/trust-anchor-did-ethr +npx solhint 'contracts/**/*.sol' +# Check .solhint.json if rules are too strict, probably not because they are relaxed currently. Can be checked with stricter rules +``` + +### Test Failures + +```bash +cd packages/trust-anchor-did-ethr +npx hardhat test +# Review error output +# Fix contracts or test files +``` + +### Build Failures + +**Contract compilation fails:** +```bash +cd packages/trust-anchor-did-ethr +npx hardhat compile +# Check Solidity syntax errors +``` + +**Frontend build fails:** +```bash +cd packages/demo-app-frontend +npm run build +# Usually TypeScript errors, so check terminal output +``` + +### CI Runs on Old Code + +**Issue:** CI fails on merged code + +**Cause:** Dependencies changed or Node.js version mismatch + +**Solution:** +```bash +# Update dependencies +npm install +# Ensure Node.js 22.12.0+ +node --version +``` + +## Future Enhancements + +**Note:** The following features are planned but not yet implemented. + +### Deployment Validation + +- Automated testnet deployments +- Contract verification on Etherscan/block explorers +- Deployment tests + +### Test Environments + +- Ethereum Sepolia testnet integration +- Secure secrets management using GitHub Secrets +- RPC endpoint configuration + + +## Contributing + +When contributing, ensure: +1. All pre-commit hooks pass +2. Run tests locally before pushing: `npm test` +3. Check CI status after pushing +4. Fix any CI failures before requesting review + +## Support + +For pipeline issues, check this document for troubleshooting steps, review GitHub Actions logs, and run commands locally to reproduce issues. + + +--- diff --git a/README.md b/README.md index 4156dde..52cddbd 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,10 @@ Get the demo application running: **1. Install Dependencies** ```bash +# Install root dependencies (Husky for pre-commit hooks) +npm install + +# Install package dependencies cd packages/trust-anchor-did-ethr && npm install cd packages/demo-app-frontend && npm install ``` @@ -117,9 +121,12 @@ npm run dev Open http://localhost:5173/ in your browser. +**Note**: This project uses pre-commit hooks (Husky) and CI checks. See [Development Workflow](BUILD.md#development-workflow) in BUILD.md for details. + ## Documentation - **[BUILD.md](BUILD.md)** - Comprehensive build instructions, testing, troubleshooting, and deployment guides +- **[CI_CD.md](CI_CD.md)** - CI/CD pipeline documentation with workflow details and troubleshooting - **[Smart Contracts](packages/trust-anchor-did-ethr/README.md)** - Detailed smart contract documentation - **[Demo Application](packages/demo-app-frontend/README.md)** - Frontend application guide diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d612e75 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,28 @@ +{ + "name": "on-chain-ssi", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "husky": "^9.1.7" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6b87ff3 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "devDependencies": { + "husky": "^9.1.7" + }, + "scripts": { + "prepare": "husky" + } +} diff --git a/packages/demo-app-frontend/.prettierignore b/packages/demo-app-frontend/.prettierignore new file mode 100644 index 0000000..69dbd04 --- /dev/null +++ b/packages/demo-app-frontend/.prettierignore @@ -0,0 +1,26 @@ +# Dependencies +node_modules + +# Build outputs +dist +build +.vite +coverage + +# Logs +*.log +npm-debug.log* + +# Lock files +package-lock.json +pnpm-lock.yaml +yarn.lock + +# Environment files +.env +.env.local +.env.production + +# Minified files +*.min.js +*.min.css diff --git a/packages/demo-app-frontend/.prettierrc b/packages/demo-app-frontend/.prettierrc new file mode 100644 index 0000000..65f51e0 --- /dev/null +++ b/packages/demo-app-frontend/.prettierrc @@ -0,0 +1,8 @@ +{ + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "printWidth": 100, + "arrowParens": "always" +} diff --git a/packages/demo-app-frontend/Dockerfile b/packages/demo-app-frontend/Dockerfile index 9b4fb92..bf3d3a9 100644 --- a/packages/demo-app-frontend/Dockerfile +++ b/packages/demo-app-frontend/Dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build the application -FROM node:20-alpine AS builder +FROM node:22-alpine AS builder WORKDIR /app diff --git a/packages/demo-app-frontend/README.md b/packages/demo-app-frontend/README.md index 117a362..acf8a29 100644 --- a/packages/demo-app-frontend/README.md +++ b/packages/demo-app-frontend/README.md @@ -34,7 +34,7 @@ You can containerize this application using the included Dockerfile (Nginx + Alp ### 1. Build the Image -*Note: The build process bakes the `.env` variables into the static files. Ensure your `.env` file is correct before building.* +_Note: The build process bakes the `.env` variables into the static files. Ensure your `.env` file is correct before building._ ```bash docker build -t ssi-frontend . @@ -75,51 +75,49 @@ The application supports two distinct user roles. Use MetaMask to switch between ### 🏛️ Role 1: Trust Anchor (Administrator) -*Use the wallet address that deployed the contracts (Account #0).* +_Use the wallet address that deployed the contracts (Account #0)._ 1. **Dashboard Overview:** -* Navigate to `/trust-anchor`. -* View real-time governance stats, quorum thresholds, and active proposals. +- Navigate to `/trust-anchor`. +- View real-time governance stats, quorum thresholds, and active proposals. 2. **Registering Companies:** -* Go to **Companies**. -* Search for a company's DID address (Wallet Address). -* If the company is "Not Managed", wait for them to delegate control. -* If they have delegated (Yellow status), scroll down to **"CRSet Admins"**. -* Paste the company's address and click **Add**. This completes the registration immediately (no proposal required). +- Go to **Companies**. +- Search for a company's DID address (Wallet Address). +- If the company is "Not Managed", wait for them to delegate control. +- If they have delegated (Yellow status), scroll down to **"CRSet Admins"**. +- Paste the company's address and click **Add**. This completes the registration immediately (no proposal required). 3. **Governance:** -* Go to **Governance**. -* Propose adding/removing admins or updating the multi-sig quorum threshold. - +- Go to **Governance**. +- Propose adding/removing admins or updating the multi-sig quorum threshold. ### 🏢 Role 2: Company (User) -*Use any other wallet address (Account #1, #2, etc.).* +_Use any other wallet address (Account #1, #2, etc.)._ 1. **Onboarding:** -* Navigate to `/company/onboarding`. -* **Step 1 (Delegate):** Sign the transaction to transfer identity ownership to the Trust Anchor. -* **Step 2 (Verification):** Wait for the Trust Anchor to approve your registration and add you as a CRSet Admin. -* **Step 3 (Complete):** Once verified, the dashboard will unlock. +- Navigate to `/company/onboarding`. +- **Step 1 (Delegate):** Sign the transaction to transfer identity ownership to the Trust Anchor. +- **Step 2 (Verification):** Wait for the Trust Anchor to approve your registration and add you as a CRSet Admin. +- **Step 3 (Complete):** Once verified, the dashboard will unlock. 2. **Revocation Management:** -* Navigate to `/company/revocations`. -* **Upload:** Drag & Drop a W3C-compliant JSON revocation list. -* **Publish:** The app uploads the file to IPFS (via Pinata) and updates the smart contract with the new CID. - +- Navigate to `/company/revocations`. +- **Upload:** Drag & Drop a W3C-compliant JSON revocation list. +- **Publish:** The app uploads the file to IPFS (via Pinata) and updates the smart contract with the new CID. --- ## 🛠 Tech Stack -* **Framework:** React + Vite -* **Language:** TypeScript -* **Web3 Integration:** Wagmi v2, Viem, TanStack Query -* **Styling:** Tailwind CSS, Lucide Icons -* **Deployment:** Docker, Nginx \ No newline at end of file +- **Framework:** React + Vite +- **Language:** TypeScript +- **Web3 Integration:** Wagmi v2, Viem, TanStack Query +- **Styling:** Tailwind CSS, Lucide Icons +- **Deployment:** Docker, Nginx diff --git a/packages/demo-app-frontend/eslint.config.js b/packages/demo-app-frontend/eslint.config.js index 5e6b472..7eb6f37 100644 --- a/packages/demo-app-frontend/eslint.config.js +++ b/packages/demo-app-frontend/eslint.config.js @@ -4,6 +4,7 @@ import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' import tseslint from 'typescript-eslint' import { defineConfig, globalIgnores } from 'eslint/config' +import eslintConfigPrettier from 'eslint-config-prettier' export default defineConfig([ globalIgnores(['dist']), @@ -14,6 +15,7 @@ export default defineConfig([ tseslint.configs.recommended, reactHooks.configs.flat.recommended, reactRefresh.configs.vite, + eslintConfigPrettier, ], languageOptions: { ecmaVersion: 2020, diff --git a/packages/demo-app-frontend/index.html b/packages/demo-app-frontend/index.html index 1ea9bd4..3318988 100644 --- a/packages/demo-app-frontend/index.html +++ b/packages/demo-app-frontend/index.html @@ -2,13 +2,20 @@
- +