diff --git a/.github/workflows/nightly-security-audit.yml b/.github/workflows/nightly-security-audit.yml new file mode 100644 index 00000000..53814fdd --- /dev/null +++ b/.github/workflows/nightly-security-audit.yml @@ -0,0 +1,76 @@ +name: Nightly Security & Mutation Audit + +on: + schedule: + # Triggers every single night at 02:00 UTC + - cron: '0 2 * * *' + workflow_dispatch: # Allows manual trigger for verification + +permissions: + contents: write + +jobs: + audit: + name: Run Security and Mutation Suite + runs-on: ubuntu-latest + + steps: + - name: Checkout Code Repository + uses: actions/checkout@v4 + + - name: Install Rust Toolchain (Nightly) + uses: dtolnay/rust-toolchain@nightly + + - name: Cache Cargo Dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-nightly-${{ hashFiles('**/Cargo.lock') }} + + - name: Install Utility Tooling Engines + run: | + cargo install cargo-deny --locked || true + cargo install cargo-audit --locked || true + cargo install cargo-mutants --locked || true + + - name: Initialize or Clear Audit Log File + run: | + echo "# 🛡️ Automated Security & Mutation Audit Log" > AUDIT_LOG.md + echo "Generated on: $(date -u)" >> AUDIT_LOG.md + echo "---" >> AUDIT_LOG.md + + - name: Execute Cargo Deny Checks + run: | + echo "## 📦 Dependency License & Advisory Checks (cargo-deny)" >> AUDIT_LOG.md + echo "\`\`\`text" >> AUDIT_LOG.md + cargo deny check licenses bans sources 2>&1 >> AUDIT_LOG.md || echo "cargo-deny failed or flagged warnings" >> AUDIT_LOG.md + echo "\`\`\`" >> AUDIT_LOG.md + echo "---" >> AUDIT_LOG.md + + - name: Execute Cargo Audit Sweeps + run: | + echo "## 🔍 Vulnerability Advisory Scans (cargo-audit)" >> AUDIT_LOG.md + echo "\`\`\`text" >> AUDIT_LOG.md + cargo audit 2>&1 >> AUDIT_LOG.md || echo "cargo-audit detected critical vulnerability markers" >> AUDIT_LOG.md + echo "\`\`\`" >> AUDIT_LOG.md + echo "---" >> AUDIT_LOG.md + + - name: Execute Cargo Mutants Quality Runs + run: | + echo "## 🧬 Mutation Testing Resilience Analytics (cargo-mutants)" >> AUDIT_LOG.md + echo "\`\`\`text" >> AUDIT_LOG.md + cargo mutants --all-features 2>&1 >> AUDIT_LOG.md || echo "cargo-mutants flagged missed mutant structures" >> AUDIT_LOG.md + echo "\`\`\`" >> AUDIT_LOG.md + + - name: Commit and Push Security Results to Repo + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add AUDIT_LOG.md + git diff-index --quiet HEAD || git commit -m "chore(ci): update nightly AUDIT_LOG.md validation tracking profiles [skip ci]" + git push origin HEAD:${{ github.ref }} \ No newline at end of file diff --git a/.github/workflows/smoke-ci.yml b/.github/workflows/smoke-ci.yml new file mode 100644 index 00000000..4010891e --- /dev/null +++ b/.github/workflows/smoke-ci.yml @@ -0,0 +1,46 @@ +name: Smoke CI Gate + +on: + push: + branches: [ main, master, develop ] + pull_request: + branches: [ main, master, develop ] + +permissions: + contents: read + +jobs: + smoke-test: + name: Code Quality & Testing Suite + runs-on: ubuntu-latest + + steps: + - name: Checkout Code Repository + uses: actions/checkout@v4 + + - name: Install Stable Rust Toolchain + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Cache Cargo Build Artifacts + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-smoke-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-smoke- + + - name: Check Code Formatting Style (fmt) + run: cargo fmt --check + + - name: Execute Static Analysis Compiler Lints (clippy) + run: cargo clippy --all-targets --all-features -- -D warnings + + - name: Run Core Verification Tests (test) + run: cargo test --all-features --workspace \ No newline at end of file diff --git a/cv-project b/cv-project new file mode 160000 index 00000000..a3e7ec5d --- /dev/null +++ b/cv-project @@ -0,0 +1 @@ +Subproject commit a3e7ec5d44e489119381ac12aeedaea7ad084e4c diff --git a/deny.toml b/deny.toml index 2c09b63b..0c0409a6 100644 --- a/deny.toml +++ b/deny.toml @@ -14,3 +14,17 @@ unknown-git = "warn" allow-registry = ["https://github.com/rust-lang/crates.io-index"] allow-git = [] +[licenses] +unlicensed = "deny" +allow = [ + "MIT", + "Apache-2.0", + "BSD-3-Clause", +] + +[bans] +multiple-versions = "warn" + +[sources] +unknown-registry = "deny" +unknown-git = "deny" \ No newline at end of file diff --git a/project_modern_ui_ux_gpt3 b/project_modern_ui_ux_gpt3 new file mode 160000 index 00000000..a201ed1b --- /dev/null +++ b/project_modern_ui_ux_gpt3 @@ -0,0 +1 @@ +Subproject commit a201ed1b248d94cc22110591b7f4ef61c456f0c8 diff --git a/propchain-dashboard/src/InsuranceAnalyticsDashboard.js b/propchain-dashboard/src/InsuranceAnalyticsDashboard.js index 9ebdde20..a0bbb156 100644 --- a/propchain-dashboard/src/InsuranceAnalyticsDashboard.js +++ b/propchain-dashboard/src/InsuranceAnalyticsDashboard.js @@ -6,6 +6,7 @@ import { Percent, ShieldCheck, TrendingUp, + Users, } from 'lucide-react'; import { Area, @@ -42,7 +43,6 @@ const getClaimRatio = (claimsPaid, premiumsCollected) => { if (!premiumsCollected) { return 0; } - return (claimsPaid / premiumsCollected) * 100; }; @@ -57,23 +57,41 @@ const MetricCard = ({ icon: Icon, label, value, detail, tone }) => ( ); -const InsuranceAnalyticsDashboard = () => { +const InsuranceAnalyticsDashboard = ({ connectedAccounts = [] }) => { + // State to manage the active multi-account context selector + const [selectedAccount, setSelectedAccount] = useState(connectedAccounts[0] || ''); const [analytics, setAnalytics] = useState(null); const [lastUpdated, setLastUpdated] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + // Fallback or update selection if the passed parent array drops or mutates + if (connectedAccounts.length > 0 && !connectedAccounts.includes(selectedAccount)) { + setSelectedAccount(connectedAccounts[0]); + } + }, [connectedAccounts, selectedAccount]); useEffect(() => { const loadAnalytics = () => { - fetchInsuranceAnalytics().then((result) => { - setAnalytics(result); - setLastUpdated(new Date()); - }); + setLoading(true); + // Pass the explicitly selected account string to slice contextual metrics + fetchInsuranceAnalytics(selectedAccount) + .then((result) => { + setAnalytics(result); + setLastUpdated(new Date()); + setLoading(false); + }) + .catch((err) => { + console.error("Failed to load insurance analytics metrics profile:", err); + setLoading(false); + }); }; loadAnalytics(); const interval = setInterval(loadAnalytics, 30000); return () => clearInterval(interval); - }, []); + }, [selectedAccount]); // Re-execute every time the active account context is flipped const summary = useMemo(() => { if (!analytics) { @@ -98,30 +116,54 @@ const InsuranceAnalyticsDashboard = () => { }; }, [analytics]); - if (!analytics || !summary) { + if (!analytics || !summary || loading) { return ( -
-

Loading insurance analytics...

+
+

+ Syncing regional risk pools and account ledger mappings... +

); } return (
-
+
-

Insurance

+

Insurance Stack Analytics

- Insurance Analytics Dashboard + Risk & Portfolio Matrix Dashboard

- {lastUpdated && ( -

- Last updated: {lastUpdated.toLocaleTimeString()} -

- )} + + {/* Multi-Account Wallet Context Switcher Menu Control */} +
+ {lastUpdated && ( +

+ Last synced: {lastUpdated.toLocaleTimeString()} +

+ )} + {connectedAccounts.length > 0 && ( +
+
+ )} +
+ {/* Metrics Breakdown Grid */}
{ />
+ {/* Charts Grid Block */}

Premiums vs Claims

-

Monthly loss-ratio trend

+

Monthly loss-ratio trend context

@@ -239,6 +282,7 @@ const InsuranceAnalyticsDashboard = () => {
+ {/* Utilization and Exposure Details */}
@@ -303,4 +347,4 @@ const InsuranceAnalyticsDashboard = () => { ); }; -export default InsuranceAnalyticsDashboard; +export default InsuranceAnalyticsDashboard; \ No newline at end of file diff --git a/propchain-dashboard/src/LendingDashboard.js b/propchain-dashboard/src/LendingDashboard.js index 90432797..dfd12380 100644 --- a/propchain-dashboard/src/LendingDashboard.js +++ b/propchain-dashboard/src/LendingDashboard.js @@ -1,69 +1,101 @@ import React, { useState, useEffect } from 'react'; -import { Activity, Landmark, AlertCircle } from 'lucide-react'; -import { fetchContractStats } from './StellarClient'; +import { logInfo, formatBalance } from './utils'; -const LendingDashboard = () => { - const [stats, setStats] = useState({ total_loaned: "0", active_loans: 0, defaults: 0 }); - const [lastUpdated, setLastUpdated] = useState(null); +export default function LendingDashboard({ connectedAccounts = [] }) { + // Fallback gracefully if no accounts are available, default to the primary address index + const [selectedAccount, setSelectedAccount] = useState(connectedAccounts[0] || ''); + const [accountData, setAccountData] = useState({ balance: 0, stake: 0, activeEscrows: [] }); + const [loading, setLoading] = useState(false); - useEffect(() => { - const fetchData = () => { - fetchContractStats().then((result) => { - // Simulate updating stats once the RPC call completes - setStats({ total_loaned: "5000", active_loans: 5, defaults: 0 }); - setLastUpdated(new Date()); - }); - }; + useEffect(() => { + if (!selectedAccount) return; + + setLoading(true); + // Simulate or query database analytics filtering elements by explicit account parameters + fetch(`/api/lending/metrics?account=${selectedAccount}`) + .then((res) => res.json()) + .then((data) => { + setAccountData(data); + setLoading(false); + }) + .catch((err) => { + console.error("Failed to resolve metrics telemetry context:", err); + setLoading(false); + }); + }, [selectedAccount]); - // Initial fetch - fetchData(); - - // Poll every 30 seconds - const interval = setInterval(fetchData, 30000); - - return () => clearInterval(interval); - }, []); - - return ( -
-

- PropChain Analytics - - - - - - Live - -

- -
-
- -

Total Volume

-

{Number(stats.total_loaned).toLocaleString()} XLM

-
- -
- -

Active Loans

-

{stats.active_loans.toLocaleString()}

-
+ return ( +
+
+
+

📊 Lending & Asset Allocation Profile

+

Real-time balance, stake metrics, and escrow monitors

+
+ + {/* Wallet Multi-Account Selector Switch */} +
+ + +
+
-
- -

Defaults

-

{stats.defaults.toLocaleString()}

-
+ {loading ? ( +
Syncing on-chain snapshot...
+ ) : ( +
+ {/* Key Metrics Row */} +
+
+ Available Floating Capital + {formatBalance(accountData.balance)} PROP
+
+ Active Lock Staking Allotment + {formatBalance(accountData.stake)} PROP +
+
- {lastUpdated && ( -

- Last updated: {lastUpdated.toLocaleTimeString()} -

+ {/* Escrow Block Component Track */} +
+

Isolated Escrow Holds ({accountData.activeEscrows.length})

+ {accountData.activeEscrows.length === 0 ? ( +

No active escrow records assigned to this address.

+ ) : ( +
+ + + + + + + + + + {accountData.activeEscrows.map((escrow) => ( + + + + + + ))} + +
Escrow IDCounterparty AddressLocked Volume
#{escrow.id}{escrow.counterparty.slice(0, 12)}...{formatBalance(escrow.amount)}
+
)} +
- ); -}; - -export default LendingDashboard; + )} +
+ ); +} \ No newline at end of file diff --git a/scripts/playground.sh b/scripts/playground.sh index ee3ea75c..7cc9c517 100755 --- a/scripts/playground.sh +++ b/scripts/playground.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# PropChain Contract Interaction Playground +# PropChain Contract Interaction Playground & Scenario Generator # # Interactive CLI for exercising the most common contract calls against a # deployed PropChain stack (property registration, escrow, staking, @@ -11,7 +11,10 @@ # scripts/deploy.sh (deployments//.json), so run # deploy.sh first (or pass an address manually when prompted). # -# Addresses issue #517. +# Automatically captures trace outputs to compile self-contained scenario +# scripts compatible with the IDE playground (docs/playground.html). +# +# Addresses issue #517 and issue #652. set -euo pipefail @@ -63,6 +66,8 @@ declare -A DEFAULT_ACCOUNTS=( SURI="${SURI:-${DEFAULT_ACCOUNTS[$NETWORK]:-}}" DEPLOYMENTS_DIR="$WORKSPACE_ROOT/deployments/$NETWORK" +OUTPUT_SCENARIO="$WORKSPACE_ROOT/docs/playground_scenario.json" +INTERACTION_LOG_TMP="/tmp/propchain_playground_session.log" # Menu option -> contract directory under contracts/ declare -A CONTRACT_DIR=( @@ -73,6 +78,10 @@ declare -A CONTRACT_DIR=( [5]="insurance" ) +# Initialize/clear temp telemetry buffer for scenario tracking +mkdir -p "$(dirname "$OUTPUT_SCENARIO")" +: > "$INTERACTION_LOG_TMP" + # --------------------------------------------------------------------------- # Usage # --------------------------------------------------------------------------- @@ -246,12 +255,53 @@ show_addresses() { local f="$DEPLOYMENTS_DIR/$dir.json" if [[ -f "$f" ]]; then echo " $dir: $(jq -r '.address' "$f")" - else + | else echo " $dir: (not deployed on $NETWORK)" fi done } +# --------------------------------------------------------------------------- +# Scenario Script Generator Pipeline (#652) +# --------------------------------------------------------------------------- +generate_playground_scenario() { + section "Compiling Playground Scenario Metadata File" + + if [ ! -s "$INTERACTION_LOG_TMP" ]; then + log_warning "No runtime interaction traces were captured during this playground session. Skipping scenario export." + return 0 + fi + + log_info "Extracting trace execution matrices..." + + # Isolate cross-contract invocations and event elements + local contract_calls + local emitted_events + contract_calls=$(grep -E "invoking|called contract|Calling" "$INTERACTION_LOG_TMP" || echo "[]") + emitted_events=$(grep -E "event|emitted|Event" "$INTERACTION_LOG_TMP" || echo "[]") + + log_info "Writing playground configuration to: $OUTPUT_SCENARIO" + + cat << EOF > "$OUTPUT_SCENARIO" +{ + "meta": { + "generator": "scripts/playground.sh", + "timestamp": "$(date -u)", + "targetEnvironment": "PropChain Interactive Engine Stack" + }, + "scenarioState": { + "network": "$NETWORK", + "signingUri": "$SURI", + "capturedTraces": { + "calls": $(echo "$contract_calls" | jq -R -s -c 'split("\n") | map(select(length > 0))' || echo "[]"), + "events": $(echo "$emitted_events" | jq -R -s -c 'split("\n") | map(select(length > 0))' || echo "[]") + } + } +} +EOF + log_success "Scenario generation complete. Compatible with docs/playground.html." +} + # --------------------------------------------------------------------------- # Contract call runner # --------------------------------------------------------------------------- @@ -274,16 +324,19 @@ run_call() { cargo contract call \ --contract "$address" \ --message "$message" \ - "${args[@]}" \ --url "${NETWORKS[$NETWORK]}" \ --suri "$SURI" \ --execute \ - --skip-confirm 2>&1 + --skip-confirm \ + "${args[@]}" 2>&1 ) local status=$? set -e echo "$output" + # Append to runtime trace log for downstream #652 generation logic + echo "--- Call Step: $message on $contract_dir ($address) ---" >> "$INTERACTION_LOG_TMP" + echo "$output" >> "$INTERACTION_LOG_TMP" if [[ $status -ne 0 ]]; then log_error "Call to $message failed (exit code $status). See output above for details." @@ -423,7 +476,7 @@ main() { echo " 4) Vote on Proposal" echo " 5) Create Insurance Policy" echo " 6) Show resolved contract addresses" - echo " 0) Exit" + echo " 0) Exit & Export Scenario" echo local choice read -r -p "Select an option: " choice @@ -435,10 +488,16 @@ main() { 4) action_vote_on_proposal ;; 5) action_create_insurance_policy ;; 6) show_addresses ;; - 0) log_info "Bye!"; exit 0 ;; + 0) + log_info "Terminating session loop..." + generate_playground_scenario + rm -f "$INTERACTION_LOG_TMP" + log_info "Bye!" + exit 0 + ;; *) log_warning "Unknown option: $choice" ;; esac done } -main "$@" +main "$@" \ No newline at end of file