diff --git a/.github/markdown-link-check-config.json b/.github/markdown-link-check-config.json new file mode 100644 index 0000000..78f6081 --- /dev/null +++ b/.github/markdown-link-check-config.json @@ -0,0 +1,23 @@ +{ + "ignorePatterns": [ + { + "pattern": "^https?://localhost" + }, + { + "pattern": "^https?://127\\.0\\.0\\.1" + } + ], + "httpHeaders": [ + { + "urls": ["https://github.com", "https://raw.githubusercontent.com"], + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml" + } + } + ], + "timeout": "10s", + "retryOn429": true, + "retryCount": 3, + "fallbackRetryDelay": "5s", + "aliveStatusCodes": [200, 201, 204, 301, 302, 303] +} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..20013cf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,90 @@ +name: CI Quality Gates + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: [master, main] + +jobs: + validate-patterns: + runs-on: ubuntu-latest + name: Validate Documentation Patterns + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: | + cd scripts + npm install + + - name: Validate pattern documents + id: validate + run: | + node scripts/validate-patterns.js + env: + CI_MODE: strict + + - name: Check markdown links + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' + config-file: '.github/markdown-link-check-config.json' + continue-on-error: true + + - name: Markdown linting + uses: DavidAnson/markdownlint-cli2-action@v16 + with: + globs: | + patterns/*.md + approaches/*.md + use-cases/*.md + vendors/*.md + continue-on-error: true + + - name: Summary + if: always() + run: | + echo "## CI Quality Gates Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f validation-report.md ]; then + cat validation-report.md >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "āœ… CI checks completed" >> $GITHUB_STEP_SUMMARY + + validate-vendors: + runs-on: ubuntu-latest + name: Validate Vendor Documentation + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Check vendor neutrality + run: | + echo "Checking vendor documentation for neutrality..." + # Check for marketing language patterns + if grep -r -i -E "(best|leading|superior|unmatched|revolutionary)" vendors/*.md 2>/dev/null; then + echo "::warning::Found potential marketing language in vendor documentation" + fi + + - name: Verify vendor cross-references + run: | + echo "Checking vendor pattern references..." + # Ensure vendors reference generic patterns, not vendor-specific ones + for file in vendors/*.md; do + if [ -f "$file" ]; then + if grep -E "pattern-.*-(flashbots|shutter|suave)" "$file" 2>/dev/null; then + echo "::error::Vendor file $file references vendor-specific pattern names" + exit 1 + fi + fi + done \ No newline at end of file diff --git a/domains/funds-assets.md b/domains/funds-assets.md index 6108a8b..7cd503b 100644 --- a/domains/funds-assets.md +++ b/domains/funds-assets.md @@ -17,7 +17,7 @@ status: draft ## Shortest-path patterns - Confidential ERC-20 on privacy L2 (FHE) + ERC-7573 (`/patterns/pattern-confidential-erc20-fhe-l2-erc7573.md`) - [L1 ZK commitment pool](../patterns/pattern-l1-zk-commitment-pool.md) -- [Crypto-registry bridge (eWpG) + EAS](../patterns/pattern-crypto-registry-bridge-eWpG-eas.md) +- [Crypto-registry bridge (eWpG) + EAS](../patterns/pattern-crypto-registry-bridge-ewpg-eas.md) - [ICMA Bond Data Taxonomy](../patterns/pattern-icma-bdt-data-model.md) - [ZK proof of derivative delta](../patterns/pattern-zk-derivative-delta.md) - [Selective disclosure (view keys + proofs)](../patterns/pattern-regulatory-disclosure-keys-proofs.md) diff --git a/domains/identity-compliance.md b/domains/identity-compliance.md index 3792af3..886ea4b 100644 --- a/domains/identity-compliance.md +++ b/domains/identity-compliance.md @@ -13,7 +13,7 @@ status: draft ## Shortest-path patterns - [zk-KYC/ML + ONCHAINID (ERC-734-735)](/patterns/pattern-zk-kyc-ml-id-erc734-735.md) - [Selective disclosure (view keys + proofs)](/patterns/pattern-regulatory-disclosure-keys-proofs.md) -- [Crypto-registry bridge (eWpG) + EAS](/patterns/pattern-crypto-registry-bridge-eWpG-eas.md) +- [Crypto-registry bridge (eWpG) + EAS](/patterns/pattern-crypto-registry-bridge-ewpg-eas.md) ## Adjacent vendors - [Chainlink ACE](/vendors/chainlink-ace.md) \ No newline at end of file diff --git a/patterns/pattern-crypto-registry-bridge-eWpG-eas.md b/patterns/pattern-crypto-registry-bridge-ewpg-eas.md similarity index 100% rename from patterns/pattern-crypto-registry-bridge-eWpG-eas.md rename to patterns/pattern-crypto-registry-bridge-ewpg-eas.md diff --git a/patterns/pattern-erc3643-rwa.md b/patterns/pattern-erc3643-rwa.md index fb81357..1f7b3a8 100644 --- a/patterns/pattern-erc3643-rwa.md +++ b/patterns/pattern-erc3643-rwa.md @@ -63,7 +63,7 @@ Enable compliant tokenization of real-world assets with built-in identity manage ## See also - [Private Bonds Approach](../approaches/approach-private-bonds.md) -- [Crypto Registry Bridge eWpG EAS](pattern-crypto-registry-bridge-eWpG-eas.md) +- [Crypto Registry Bridge eWpG EAS](pattern-crypto-registry-bridge-ewpg-eas.md) - [Regulatory Disclosure Keys Proofs](pattern-regulatory-disclosure-keys-proofs.md) - [ZK KYC ML ID ERC734-735](pattern-zk-kyc-ml-id-erc734-735.md) - [ERC-3643 Documentation](https://docs.erc3643.org/erc-3643) diff --git a/patterns/pattern-icma-bdt-data-model.md b/patterns/pattern-icma-bdt-data-model.md index 5595794..55fee58 100644 --- a/patterns/pattern-icma-bdt-data-model.md +++ b/patterns/pattern-icma-bdt-data-model.md @@ -35,7 +35,7 @@ Use **ICMA Bond Data Taxonomy** as the canonical schema for bond terms & lifecyc - Issuance terms in BDT; hash anchored via EAS; regulator verifies consistency. ## See also -- pattern-crypto-registry-bridge-eWpG-eas.md +- pattern-crypto-registry-bridge-ewpg-eas.md ## See also (external) - ICMA BDT overview: https://www.icmagroup.org/fintech-and-digitalisation/fintech-advisory-committee-and-related-groups/bond-data-taxonomy/ diff --git a/patterns/pattern-permissioned-ledger-interoperability.md b/patterns/pattern-permissioned-ledger-interoperability.md index 6aab040..02b21aa 100644 --- a/patterns/pattern-permissioned-ledger-interoperability.md +++ b/patterns/pattern-permissioned-ledger-interoperability.md @@ -59,4 +59,4 @@ Enable atomic transactions and data exchange across distinct permissioned ledger - Pattern: [DvP ERC-7573](../patterns/pattern-dvp-erc7573.md) - Pattern: [Private ISO20022](../patterns/pattern-private-iso20022.md) -- Pattern: [Crypto-Registry Bridge eWpG-EAS](../patterns/pattern-crypto-registry-bridge-eWpG-eas.md) +- Pattern: [Crypto-Registry Bridge eWpG-EAS](../patterns/pattern-crypto-registry-bridge-ewpg-eas.md) diff --git a/patterns/pattern-pretrade-privacy-shutter-suave.md b/patterns/pattern-pretrade-privacy-encryption.md similarity index 100% rename from patterns/pattern-pretrade-privacy-shutter-suave.md rename to patterns/pattern-pretrade-privacy-encryption.md diff --git a/patterns/pattern-stealth-adresses.md b/patterns/pattern-stealth-addresses.md similarity index 92% rename from patterns/pattern-stealth-adresses.md rename to patterns/pattern-stealth-addresses.md index 9bc005a..536dd0a 100644 --- a/patterns/pattern-stealth-adresses.md +++ b/patterns/pattern-stealth-addresses.md @@ -9,9 +9,9 @@ avoid-when: - Strong amount confidentiality is required (use shielded pools or confidential tokens). - Institutions require regulator keys / scoped audit by default. dependencies: - - [ERC-20](https://eips.ethereum.org/EIPS/eip-20) - - [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) (optional, account abstraction for wallet UX) - - [EIP-5564](https://eips.ethereum.org/EIPS/eip-5564) (Ethereum Stealth Addresses draft) + - ERC-20 + - ERC-4337 (optional, account abstraction for wallet UX) + - EIP-5564 (Ethereum Stealth Addresses draft) --- ## Intent diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 0000000..13c8610 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +package-lock.json +validation-report.md \ No newline at end of file diff --git a/scripts/package.json b/scripts/package.json new file mode 100644 index 0000000..0284adf --- /dev/null +++ b/scripts/package.json @@ -0,0 +1,17 @@ +{ + "name": "iptf-map-validation", + "version": "1.0.0", + "description": "Validation scripts for IPTF Map documentation", + "main": "validate-patterns.js", + "scripts": { + "validate": "node validate-patterns.js", + "validate:ci": "CI_MODE=strict node validate-patterns.js" + }, + "dependencies": { + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "license": "CC0" +} \ No newline at end of file diff --git a/scripts/validate-patterns.js b/scripts/validate-patterns.js new file mode 100644 index 0000000..17c6ee7 --- /dev/null +++ b/scripts/validate-patterns.js @@ -0,0 +1,243 @@ +#!/usr/bin/env node +/** + * Pattern Validation Script for IPTF Map + * Validates pattern and vendor documents against PRD requirements + */ + +const fs = require('fs'); +const path = require('path'); +const yaml = require('js-yaml'); + +// Configuration +const PATTERNS_DIR = path.join(__dirname, '..', 'patterns'); +const VENDORS_DIR = path.join(__dirname, '..', 'vendors'); +const IS_CI = process.env.CI_MODE === 'strict'; + +// Required frontmatter fields for patterns +const REQUIRED_PATTERN_FRONTMATTER = [ + 'title', + 'status', + 'maturity' +]; + +// New frontmatter fields (warn only for now) +const RECOMMENDED_PATTERN_FRONTMATTER = [ + 'layer', + 'privacy_goal', + 'assumptions', + 'last_reviewed' +]; + +// Required sections in pattern documents +const REQUIRED_PATTERN_SECTIONS = [ + '## Intent', + '## Ingredients', + '## Protocol', + '## Guarantees', + '## Trade-offs', + '## Example', + '## See also' +]; + +// Validation results +let errors = []; +let warnings = []; + +/** + * Parse markdown file and extract frontmatter and content + */ +function parseMarkdown(filePath) { + const content = fs.readFileSync(filePath, 'utf8'); + const lines = content.split('\n'); + + let frontmatter = {}; + let markdownContent = ''; + let inFrontmatter = false; + let frontmatterLines = []; + + for (let i = 0; i < lines.length; i++) { + if (i === 0 && lines[i] === '---') { + inFrontmatter = true; + continue; + } + + if (inFrontmatter && lines[i] === '---') { + inFrontmatter = false; + try { + frontmatter = yaml.load(frontmatterLines.join('\n')) || {}; + } catch (e) { + errors.push(`${filePath}: Invalid YAML frontmatter - ${e.message}`); + } + continue; + } + + if (inFrontmatter) { + frontmatterLines.push(lines[i]); + } else if (!inFrontmatter && lines[i] !== '---') { + markdownContent += lines[i] + '\n'; + } + } + + return { frontmatter, content: markdownContent }; +} + +/** + * Validate pattern file naming convention + */ +function validatePatternFileName(fileName) { + if (!fileName.startsWith('pattern-')) { + return 'Pattern files must start with "pattern-"'; + } + + if (!fileName.endsWith('.md')) { + return 'Pattern files must end with ".md"'; + } + + const nameWithoutExtension = fileName.slice(0, -3); + if (!/^pattern-[a-z0-9-]+$/.test(nameWithoutExtension)) { + return 'Pattern names must use kebab-case (lowercase letters, numbers, and hyphens only)'; + } + + // Check for vendor-specific names + const vendorSpecificPatterns = ['flashbots', 'shutter', 'suave', 'aztec', 'polygon']; + for (const vendor of vendorSpecificPatterns) { + if (fileName.includes(vendor)) { + return `Pattern name contains vendor-specific term "${vendor}" - use generic names instead`; + } + } + + return null; +} + +/** + * Validate a single pattern file + */ +function validatePattern(filePath) { + const fileName = path.basename(filePath); + const { frontmatter, content } = parseMarkdown(filePath); + const fileErrors = []; + const fileWarnings = []; + + // Skip template and README files + if (fileName === '_template.md' || fileName === 'README.md') { + return; + } + + // Validate file naming + const namingError = validatePatternFileName(fileName); + if (namingError) { + fileErrors.push(namingError); + } + + // Validate required frontmatter + for (const field of REQUIRED_PATTERN_FRONTMATTER) { + if (!frontmatter[field]) { + fileErrors.push(`Missing required frontmatter field: ${field}`); + } + } + + // Check recommended frontmatter (warnings only) + for (const field of RECOMMENDED_PATTERN_FRONTMATTER) { + if (!frontmatter[field]) { + fileWarnings.push(`Missing recommended frontmatter field: ${field}`); + } + } + + // Validate frontmatter values + if (frontmatter.status && !['draft', 'ready'].includes(frontmatter.status)) { + fileErrors.push(`Invalid status value: ${frontmatter.status} (must be 'draft' or 'ready')`); + } + + if (frontmatter.maturity && !['experimental', 'PoC', 'pilot', 'production', 'prod'].includes(frontmatter.maturity)) { + fileWarnings.push(`Unexpected maturity value: ${frontmatter.maturity}`); + } + + // Validate required sections + for (const section of REQUIRED_PATTERN_SECTIONS) { + if (!content.includes(section)) { + // For existing patterns, only warn about missing sections + const isNewPattern = !fs.existsSync(filePath.replace('feature/ci-infrastructure', 'master')); + if (IS_CI && isNewPattern) { + fileErrors.push(`Missing required section: ${section}`); + } else { + fileWarnings.push(`Missing required section: ${section}`); + } + } + } + + // Report errors and warnings + if (fileErrors.length > 0) { + errors.push(`\nāŒ ${fileName}:\n ${fileErrors.join('\n ')}`); + } + + if (fileWarnings.length > 0) { + warnings.push(`\nāš ļø ${fileName}:\n ${fileWarnings.join('\n ')}`); + } +} + +/** + * Validate all patterns in the patterns directory + */ +function validateAllPatterns() { + console.log('šŸ” Validating pattern documents...\n'); + + const files = fs.readdirSync(PATTERNS_DIR); + const patternFiles = files.filter(f => f.endsWith('.md')); + + for (const file of patternFiles) { + const filePath = path.join(PATTERNS_DIR, file); + validatePattern(filePath); + } +} + +/** + * Generate validation report + */ +function generateReport() { + const report = []; + + report.push('### Pattern Validation Report\n'); + + if (errors.length === 0 && warnings.length === 0) { + report.push('āœ… All patterns pass validation!\n'); + } else { + if (errors.length > 0) { + report.push(`#### Errors (${errors.length})`); + report.push(...errors); + report.push(''); + } + + if (warnings.length > 0) { + report.push(`#### Warnings (${warnings.length})`); + report.push(...warnings); + report.push(''); + } + } + + // Write report for GitHub Actions summary + fs.writeFileSync('validation-report.md', report.join('\n')); + + // Console output + console.log(report.join('\n')); +} + +/** + * Main execution + */ +function main() { + try { + validateAllPatterns(); + generateReport(); + + // Exit with error if there are validation errors in CI mode + if (IS_CI && errors.length > 0) { + process.exit(1); + } + } catch (error) { + console.error('Validation script error:', error); + process.exit(1); + } +} + +// Run validation +main(); \ No newline at end of file diff --git a/vendors/chainlink-ace.md b/vendors/chainlink-ace.md index afcef91..fbde98d 100644 --- a/vendors/chainlink-ace.md +++ b/vendors/chainlink-ace.md @@ -10,7 +10,7 @@ Modular compliance layer built on the Chainlink Runtime Environment (CRE) to def ## Fits with patterns (names only) - [Regulatory Disclosure Keys Proofs](../patterns/pattern-regulatory-disclosure-keys-proofs.md) -- [Crypto Registry Bridge eWpG EAS](../patterns/pattern-crypto-registry-bridge-eWpG-eas.md) +- [Crypto Registry Bridge eWpG EAS](../patterns/pattern-crypto-registry-bridge-ewpg-eas.md) - [DvP ERC7573](../patterns/pattern-dvp-erc7573.md) ## Not a substitute for diff --git a/vendors/flashbots.md b/vendors/flashbots.md index 5848bf2..9b187d8 100644 --- a/vendors/flashbots.md +++ b/vendors/flashbots.md @@ -16,7 +16,7 @@ Flashbots develops **MEV infrastructure** including private mempools, block buil ## Key Use Cases / Patterns -- [Pre-trade Privacy](../patterns/pattern-pretrade-privacy-shutter-suave.md) - Private intent expression via SUAVE +- [Pre-trade Privacy](../patterns/pattern-pretrade-privacy-encryption.md) - Private intent expression via SUAVE - [Private Broadcasting](../approaches/approach-private-broadcasting.md) - MEV protection through private mempools ## Technical Approach diff --git a/vendors/paladin.md b/vendors/paladin.md index 1d08328..a75f613 100644 --- a/vendors/paladin.md +++ b/vendors/paladin.md @@ -21,7 +21,7 @@ A strong design principle of the project is that existing privacy preserving tok - [L1 ZK Commitment Pool](../patterns/pattern-l1-zk-commitment-pool.md) - [DvP ERC7573](../patterns/pattern-dvp-erc7573.md) - [Confidential ERC20 FHE L2 ERC7573](../patterns/pattern-confidential-erc20-fhe-l2-erc7573.md) -- [Crypto Registry Bridge eWpG EAS](../patterns/pattern-crypto-registry-bridge-eWpG-eas.md) +- [Crypto Registry Bridge eWpG EAS](../patterns/pattern-crypto-registry-bridge-ewpg-eas.md) ## Not a substitute for - Privacy L2 or App-chain diff --git a/vendors/shutter.md b/vendors/shutter.md index 71630d3..116b2c3 100644 --- a/vendors/shutter.md +++ b/vendors/shutter.md @@ -16,7 +16,7 @@ Shutter Network provides **encrypted mempool** infrastructure that prevents MEV ## Key Use Cases / Patterns -- [Pre-trade Privacy](../patterns/pattern-pretrade-privacy-shutter-suave.md) - Encrypted mempool with threshold decryption +- [Pre-trade Privacy](../patterns/pattern-pretrade-privacy-encryption.md) - Encrypted mempool with threshold decryption - [Private Broadcasting](../approaches/approach-private-broadcasting.md) - Intent signaling protection ## Technical Approach