feat: Add comprehensive GitHub security integration

Security Infrastructure:
- Add .gitattributes for merge conflict protection and sensitive file handling
- Add SECURITY.md with detailed security policies and procedures
- Add pre-commit hook template for local secret detection
- Add GitHub Actions workflow for automated security scanning
- Add comprehensive documentation for git hooks

Code Security Improvements:
- Fix AuthContext.tsx: Remove hardcoded credentials, use environment variables
- Migrate WalletContext.tsx: Replace Ethereum/MetaMask with Polkadot.js
- Refactor lib/wallet.ts: Complete Substrate configuration with asset management
- Update TokenSwap.tsx: Add real API integration for balance queries
- Update StakingDashboard.tsx: Add blockchain integration placeholders

Environment Management:
- Update .env with proper security warnings
- Update .env.example with comprehensive template
- All sensitive data now uses environment variables
- Demo mode controllable via VITE_ENABLE_DEMO_MODE flag

Security Measures Implemented:
 4-layer protection (gitignore + gitattributes + pre-commit + CI/CD)
 Automated secret scanning (TruffleHog + Gitleaks)
 Pre-commit hooks prevent accidental commits
 CI/CD pipeline validates all PRs
 Environment variable validation
 Dependency security auditing

Breaking Changes:
- WalletContext now uses Polkadot.js instead of MetaMask
- lib/wallet.ts completely rewritten for Substrate
- ASSET_IDs and CHAIN_CONFIG exported from lib/wallet.ts
- Demo mode must be explicitly enabled

Migration Notes:
- Install pre-commit hook: cp .git-hooks/pre-commit.example .git/hooks/pre-commit
- Copy environment: cp .env.example .env
- Update .env with your credentials
- Enable GitHub Actions in repository settings

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-28 21:48:48 +03:00
parent 9dea336f92
commit 93767711d9
13 changed files with 1652 additions and 299 deletions
+7 -5
View File
@@ -1,11 +1,13 @@
import { createClient } from '@supabase/supabase-js';
// Initialize Supabase client from environment variables
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseKey) {
console.warn('Supabase credentials not found in environment variables');
}
// Initialize Supabase client
// Using direct values from project configuration
const supabaseUrl = 'https://vbhftvdayqfmcgmzdxfv.supabase.co';
const supabaseKey = 'sb_publishable_Aq6cShprdtxYyUsohmsquQ_OurU7w07';
const supabase = createClient(supabaseUrl, supabaseKey);
export { supabase };
+114 -26
View File
@@ -1,49 +1,137 @@
// Wallet configuration and utilities for PezkuwiChain
export const PEZKUWICHAIN_NETWORK = {
chainId: '0x2329', // 9001 in hex
chainName: 'PezkuwiChain',
nativeCurrency: {
name: 'Pezkuwi',
symbol: 'PZK',
decimals: 18
},
rpcUrls: ['https://rpc.pezkuwichain.app'],
blockExplorerUrls: ['https://explorer.pezkuwichain.app']
// ========================================
// PezkuwiChain - Substrate/Polkadot.js Configuration
// ========================================
// This file configures wallet connectivity for Substrate-based chains
import type { InjectedAccountWithMeta } from '@polkadot/extension-inject/types';
// ========================================
// NETWORK ENDPOINTS
// ========================================
export const NETWORK_ENDPOINTS = {
local: import.meta.env.VITE_DEVELOPMENT_WS || 'ws://127.0.0.1:9944',
testnet: import.meta.env.VITE_TESTNET_WS || 'wss://testnet.pezkuwichain.io',
mainnet: import.meta.env.VITE_MAINNET_WS || 'wss://mainnet.pezkuwichain.io',
staging: import.meta.env.VITE_STAGING_WS || 'wss://staging.pezkuwichain.io',
beta: import.meta.env.VITE_BETA_WS || 'wss://beta.pezkuwichain.io',
};
// ========================================
// CHAIN CONFIGURATION
// ========================================
export const CHAIN_CONFIG = {
name: import.meta.env.VITE_CHAIN_NAME || 'PezkuwiChain',
symbol: import.meta.env.VITE_CHAIN_TOKEN_SYMBOL || 'PEZ',
decimals: parseInt(import.meta.env.VITE_CHAIN_TOKEN_DECIMALS || '12'),
ss58Format: parseInt(import.meta.env.VITE_CHAIN_SS58_FORMAT || '42'),
};
// ========================================
// SUBSTRATE ASSET IDs (Assets Pallet)
// ========================================
export const ASSET_IDS = {
PEZ: parseInt(import.meta.env.VITE_ASSET_PEZ || '1'),
HEZ: parseInt(import.meta.env.VITE_ASSET_HEZ || '2'),
USDT: parseInt(import.meta.env.VITE_ASSET_USDT || '3'),
BTC: parseInt(import.meta.env.VITE_ASSET_BTC || '4'),
ETH: parseInt(import.meta.env.VITE_ASSET_ETH || '5'),
DOT: parseInt(import.meta.env.VITE_ASSET_DOT || '6'),
} as const;
// ========================================
// EXPLORER URLS
// ========================================
export const EXPLORER_URLS = {
polkadotJs: import.meta.env.VITE_EXPLORER_URL || 'https://polkadot.js.org/apps/?rpc=',
custom: import.meta.env.VITE_CUSTOM_EXPLORER_URL || 'https://explorer.pezkuwichain.io',
};
// ========================================
// WALLET ERROR MESSAGES
// ========================================
export const WALLET_ERRORS = {
NO_WALLET: 'No wallet detected. Please install MetaMask or use WalletConnect.',
NO_EXTENSION: 'No Polkadot.js extension detected. Please install Polkadot.js or compatible wallet.',
NO_ACCOUNTS: 'No accounts found. Please create an account in your wallet extension.',
CONNECTION_FAILED: 'Failed to connect wallet. Please try again.',
NETWORK_ERROR: 'Failed to switch network. Please add PezkuwiChain manually.',
TRANSACTION_FAILED: 'Transaction failed. Please check your balance and try again.',
USER_REJECTED: 'User rejected the request.'
USER_REJECTED: 'User rejected the request.',
INSUFFICIENT_BALANCE: 'Insufficient balance to complete transaction.',
INVALID_ADDRESS: 'Invalid address format.',
API_NOT_READY: 'Blockchain API not ready. Please wait...',
};
// ========================================
// UTILITY FUNCTIONS
// ========================================
/**
* Format Substrate address for display (SS58 format)
* @param address - Full substrate address
* @returns Shortened address string (e.g., "5GrwV...xQjz")
*/
export const formatAddress = (address: string): string => {
if (!address) return '';
return `${address.slice(0, 6)}...${address.slice(-4)}`;
};
export const formatBalance = (balance: string, decimals = 18): string => {
/**
* Format balance from planck to human-readable format
* @param balance - Balance in smallest unit (planck)
* @param decimals - Token decimals (default 12 for PEZ)
* @returns Formatted balance string
*/
export const formatBalance = (balance: string | number, decimals = 12): string => {
if (!balance) return '0';
const value = parseFloat(balance) / Math.pow(10, decimals);
return value.toFixed(4);
const value = typeof balance === 'string' ? parseFloat(balance) : balance;
return (value / Math.pow(10, decimals)).toFixed(4);
};
export interface WalletState {
/**
* Parse human-readable amount to planck (smallest unit)
* @param amount - Human-readable amount
* @param decimals - Token decimals
* @returns Amount in planck
*/
export const parseAmount = (amount: string | number, decimals = 12): bigint => {
const value = typeof amount === 'string' ? parseFloat(amount) : amount;
return BigInt(Math.floor(value * Math.pow(10, decimals)));
};
/**
* Get asset symbol by ID
* @param assetId - Asset ID from Assets pallet
* @returns Asset symbol or 'UNKNOWN'
*/
export const getAssetSymbol = (assetId: number): string => {
const entry = Object.entries(ASSET_IDS).find(([_, id]) => id === assetId);
return entry ? entry[0] : 'UNKNOWN';
};
/**
* Get current network endpoint based on VITE_NETWORK env
* @returns WebSocket endpoint URL
*/
export const getCurrentEndpoint = (): string => {
const network = import.meta.env.VITE_NETWORK || 'local';
return NETWORK_ENDPOINTS[network as keyof typeof NETWORK_ENDPOINTS] || NETWORK_ENDPOINTS.local;
};
// ========================================
// TYPE DEFINITIONS
// ========================================
export interface PolkadotWalletState {
isConnected: boolean;
address: string | null;
accounts: InjectedAccountWithMeta[];
selectedAccount: InjectedAccountWithMeta | null;
balance: string;
chainId: string | null;
provider: any;
error: string | null;
}
export const initialWalletState: WalletState = {
export const initialPolkadotWalletState: PolkadotWalletState = {
isConnected: false,
address: null,
accounts: [],
selectedAccount: null,
balance: '0',
chainId: null,
provider: null,
error: null
error: null,
};