Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
2638a9f
docs: add operational runbooks (#315)
devnWisdom May 29, 2026
7881a7e
feat(web): real-time energy chart with WebSocket + polling fallback (…
pauljacobb May 31, 2026
18c472a
docs(contracts): add/enhance Rust doc comments on all public function…
pauljacobb May 31, 2026
eb1a425
docs: add user guide for web dashboard (closes #317)
Magada06 May 31, 2026
9b2ce49
feat(security): add RLS policies for multi-tenant isolation (#274)
Magada06 May 31, 2026
3fc2fcd
feat: add loading skeletons for async data fetches (#255)
Magada06 May 31, 2026
b1d6e5f
ci: add dedicated Contracts CI workflow (#287)
Philzwrist07 May 31, 2026
29135d5
feat(testing): add mutation testing for Rust contracts and TS utiliti…
Philzwrist07 May 31, 2026
861bcce
feat: implement certificate retirement API endpoint (#270)
devAgatha Jun 1, 2026
ecda905
feat(governance): configurable quorum/threshold with admin guard and …
jhayniffy Jun 1, 2026
2b79205
feat(crypto): add verifyReadingSignature and 100% unit test coverage
jhayniffy Jun 1, 2026
fa8bf84
feat(api): versioning — 301 redirects from /api/* to /api/v1/*, API-V…
jhayniffy Jun 1, 2026
164dbc7
feat(ci): Docker image scanning with Trivy — block on CRITICAL CVEs
jhayniffy Jun 1, 2026
7e37584
feat(db): add perf indexes on readings, certificates, audit_anchors
jhayniffy Jun 1, 2026
5ae1a9e
ci: automate Vercel production deploy gated on CI
jhayniffy Jun 1, 2026
a1ec4b7
fix: resolve JSX parse errors in dashboard and verify pages
jhayniffy Jun 1, 2026
515ed8d
feat(governance): add proposed_action field to create proposal form
jhayniffy Jun 1, 2026
1d6db6b
fix(security): add security headers to all HTTP responses (#340)
JosephOnuh Jun 1, 2026
2834203
fix(security): implement CSP headers for Next.js web app (#333)
JosephOnuh Jun 1, 2026
ab4b39e
fix(ci): add dependency license compliance check (#344)
JosephOnuh Jun 1, 2026
34d0971
fix(security): implement audit logging for sensitive operations (#341)
JosephOnuh Jun 1, 2026
477a577
feat: certificate transfer endpoint and UI (#1)
jhayniffy Jun 1, 2026
325b565
feat: mock Freighter wallet for CI testing (#2)
jhayniffy Jun 1, 2026
0d90853
test: tracer-sim integration tests (#3)
jhayniffy Jun 1, 2026
232bf4a
feat: I-REC XML export for certificates (#4)
jhayniffy Jun 1, 2026
1ecf24e
feat(e2e): add Playwright tests for dashboard, certificate detail, an…
jhayniffy Jun 1, 2026
d4117a7
feat(auth): configure token expiry, rotation, and revocation list
jhayniffy Jun 1, 2026
45c9c81
feat(security): HTTPS redirect and HSTS headers
jhayniffy Jun 1, 2026
71dc4a9
feat: add public v1 verify API and OpenAPI spec (#352)
Sammy-Samy Jun 1, 2026
d27703e
feat: add pentest scope and report placeholder (#342)
Sammy-Samy Jun 1, 2026
196ab0c
feat: add bulk certificate retirement API and UI (#347)
Sammy-Samy Jun 1, 2026
4205191
feat: implement webhook notifications for certificate lifecycle event…
Sammy-Samy Jun 1, 2026
84ee9a6
feat: support fractional kWh tokens with 3 decimal places
Dev-Odun-oss Jun 1, 2026
d5416fd
fix issue 137 & 138
Benalex8797 Jun 1, 2026
49bd5fe
feat: admin interface and fractional kWh support
doradenise-jpg Jun 1, 2026
944c5b9
feat(security): add HTTP security headers (#129)
woodlonestar-lang Jun 2, 2026
a437a9b
feat(security): API key auth for meter submissions (#131)
woodlonestar-lang Jun 2, 2026
037e825
feat(security): restrict Supabase service role key usage (#134)
woodlonestar-lang Jun 2, 2026
7ce4a12
feat(notifications): email alerts for mint, retire, and mint failure …
woodlonestar-lang Jun 2, 2026
cb1f85b
update
confima-source Jun 2, 2026
7664eda
Configure environment-specific secrets management (#289)
ladinoraa Jun 2, 2026
643ff2d
Configure environment-specific secrets management (#289)
ladinoraa Jun 2, 2026
a7123fc
Configure environment-specific secrets management (#289)
ladinoraa Jun 2, 2026
66ba015
updates on proofwork
confima-source Jun 2, 2026
fb2e059
chore(deps): bump the patch-updates group with 6 updates (#449)
dependabot[bot] Jun 3, 2026
8af8479
chore(deps): bump the minor-updates group with 2 updates
dependabot[bot] Jun 3, 2026
1785971
Merge branch 'main' into dependabot/npm_and_yarn/minor-updates-ce4d04…
AnnabelJoe Jun 3, 2026
8ebc708
Merge pull request #450 from AnnabelJoe/dependabot/npm_and_yarn/minor…
AnnabelJoe Jun 3, 2026
91fc2b9
Merge pull request #448 from confima-source/feature/proofwork
AnnabelJoe Jun 3, 2026
8a2f59f
Merge pull request #447 from ladinoraa/issue-289-secrets-management
AnnabelJoe Jun 3, 2026
1b7d948
Merge pull request #446 from confima-source/feature/proof
AnnabelJoe Jun 3, 2026
6c51623
Merge branch 'main' into feature/security
AnnabelJoe Jun 3, 2026
48c6da7
Merge pull request #445 from woodlonestar-lang/feature/security
AnnabelJoe Jun 3, 2026
40e300d
Merge branch 'main' into feat/admin-ui-fractional-kwh
AnnabelJoe Jun 3, 2026
22924a2
Merge pull request #444 from doradenise-jpg/feat/admin-ui-fractional-kwh
AnnabelJoe Jun 3, 2026
ecccc4e
Merge branch 'main' into feat/fix
AnnabelJoe Jun 3, 2026
257fc75
Merge pull request #443 from devmasalati/feat/fix
AnnabelJoe Jun 3, 2026
5a92434
Merge branch 'main' into feat/fractional-kwh-tokens-354
AnnabelJoe Jun 3, 2026
e4544b7
Merge pull request #442 from Dev-Odun-oss/feat/fractional-kwh-tokens-354
AnnabelJoe Jun 3, 2026
a09f487
Merge branch 'main' into fix/e2e-token-expiry-https
AnnabelJoe Jun 3, 2026
f7d72b0
Merge pull request #441 from devoclan/fix/e2e-token-expiry-https
AnnabelJoe Jun 3, 2026
3fa702e
Merge branch 'main' into feat/issue-353-webhook-notifications
AnnabelJoe Jun 3, 2026
ceabb58
Merge pull request #440 from Sammy-Samy/feat/issue-353-webhook-notifi…
AnnabelJoe Jun 3, 2026
1845970
Merge pull request #439 from Sammy-Samy/feat/issue-347-bulk-retirement
AnnabelJoe Jun 3, 2026
315cb59
Merge pull request #438 from Sammy-Samy/feat/issue-342-pentest
AnnabelJoe Jun 3, 2026
c74344f
Merge pull request #437 from Sammy-Samy/feat/issue-352-public-verify-api
AnnabelJoe Jun 3, 2026
1cb7897
Merge branch 'main' into feature/issues-transfer-wallet-tracer-irec
AnnabelJoe Jun 3, 2026
049b764
Merge pull request #436 from jhayniffy/feature/issues-transfer-wallet…
AnnabelJoe Jun 3, 2026
1b86703
Merge branch 'main' into fix/341-audit-logging
AnnabelJoe Jun 3, 2026
4c6cc64
Merge pull request #435 from JosephOnuh/fix/341-audit-logging
AnnabelJoe Jun 3, 2026
b89dd7e
Merge pull request #434 from JosephOnuh/fix/344-license-compliance
AnnabelJoe Jun 3, 2026
7367043
Merge branch 'main' into fix/333-csp-headers
AnnabelJoe Jun 3, 2026
abd9139
Merge pull request #433 from JosephOnuh/fix/333-csp-headers
AnnabelJoe Jun 3, 2026
2019cd8
Merge branch 'main' into fix/340-security-headers
AnnabelJoe Jun 3, 2026
e061c41
Merge pull request #432 from JosephOnuh/fix/340-security-headers
AnnabelJoe Jun 3, 2026
578c482
Merge pull request #431 from josunday002/jobsunday
AnnabelJoe Jun 3, 2026
ac14fb9
Merge pull request #430 from sundayjob996/sundayjob
AnnabelJoe Jun 3, 2026
d279de3
Merge branch 'main' into feat/270-certificate-retirement
AnnabelJoe Jun 3, 2026
455bc44
Merge pull request #429 from devAgatha/feat/270-certificate-retirement
AnnabelJoe Jun 3, 2026
b20cb8e
Merge pull request #420 from Magada06/feature/274-rls-policies
AnnabelJoe Jun 3, 2026
c4c4466
Merge branch 'main' into issue-331-mutation-testing
AnnabelJoe Jun 3, 2026
cecac18
Merge pull request #425 from Philzwrist07/issue-331-mutation-testing
AnnabelJoe Jun 3, 2026
ca0a76d
Merge branch 'main' into docs/317-user-guide
AnnabelJoe Jun 3, 2026
4f6c85c
Merge pull request #419 from Magada06/docs/317-user-guide
AnnabelJoe Jun 3, 2026
acdb9b2
Merge pull request #422 from Philzwrist07/feat/287-contracts-ci
AnnabelJoe Jun 3, 2026
20f951f
Merge branch 'main' into issue-255-loading-skeletons
AnnabelJoe Jun 3, 2026
d9a528d
Merge pull request #421 from Magada06/issue-255-loading-skeletons
AnnabelJoe Jun 3, 2026
2b0a164
Merge pull request #389 from devnWisdom/docs/operational-runbooks-315
AnnabelJoe Jun 3, 2026
7a94632
Merge pull request #416 from pauljacobb/feat/260-realtime-chart-webso…
AnnabelJoe Jun 3, 2026
6be6abf
Merge branch 'main' into docs/319-rust-doc-comments
AnnabelJoe Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 60 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ jobs:
- run: pnpm build
working-directory: apps/web
env:
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL || 'https://placeholder.supabase.co' }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY || 'placeholder' }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
NEXT_PUBLIC_STELLAR_NETWORK: testnet
NEXT_PUBLIC_ENERGY_TOKEN_ID: placeholder
NEXT_PUBLIC_AUDIT_REGISTRY_ID: placeholder
NEXT_PUBLIC_COMMUNITY_GOVERNANCE_ID: placeholder
SUPABASE_SERVICE_ROLE_KEY: placeholder
MINTER_SECRET_KEY: SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
MINTER_SECRET_KEY: ${{ secrets.MINTER_SECRET_KEY }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}

Expand Down Expand Up @@ -104,6 +104,21 @@ jobs:
- name: Validate openapi.yaml
run: npx --yes @redocly/cli@1 lint openapi.yaml --format=github-actions

license-compliance:
name: License compliance check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: npx license-checker --onlyAllow "$(node -e "const c=require('./.license-checker.json');console.log(c.allowedLicenses.join(';'))")" --excludePrivatePackages

contracts:
name: Contracts (fmt + clippy + test)
runs-on: ubuntu-latest
Expand Down Expand Up @@ -177,3 +192,44 @@ jobs:
- name: fuzz_vote (30 s)
run: cargo fuzz run fuzz_vote -- -max_total_time=30 corpus/fuzz_vote
working-directory: apps/contracts/fuzz

image-scan:
name: Docker image vulnerability scan (Trivy)
runs-on: ubuntu-latest
needs: web
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4

- name: Build Docker image
run: |
docker build \
--file apps/web/Dockerfile \
--tag solarproof/web:${{ github.sha }} \
.

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.28.0
with:
image-ref: solarproof/web:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL
exit-code: '1'
ignore-unfixed: true

- name: Upload Trivy SARIF results as artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: trivy-scan-results
path: trivy-results.sarif
retention-days: 30

- name: Upload SARIF to GitHub Security tab
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif
48 changes: 48 additions & 0 deletions .github/workflows/contracts-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Contracts CI

on:
pull_request:
branches: [main, develop]
paths:
- "apps/contracts/**"
- ".github/workflows/contracts-ci.yml"
push:
branches: [main, develop]
paths:
- "apps/contracts/**"
- ".github/workflows/contracts-ci.yml"

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Rust contracts (fmt + clippy + test)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.85.0"
targets: wasm32-unknown-unknown
components: rustfmt, clippy

- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: apps/contracts

- name: Check formatting
run: cargo fmt --all -- --check
working-directory: apps/contracts

- name: Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
working-directory: apps/contracts

- name: Run tests
run: cargo test --all
working-directory: apps/contracts
49 changes: 49 additions & 0 deletions .github/workflows/deploy-production.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Deploy Production

on:
push:
branches: [main]

jobs:
ci:
name: CI gate
uses: ./.github/workflows/ci.yml
secrets: inherit

deploy:
name: Deploy to Vercel (production)
runs-on: ubuntu-latest
needs: ci
permissions:
deployments: write
environment:
name: production
url: ${{ steps.promote.outputs.url }}
steps:
- uses: actions/checkout@v4

- name: Install Vercel CLI
run: npm install -g vercel@latest

- name: Build & deploy preview (green)
id: deploy
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
run: |
url=$(vercel deploy --token "$VERCEL_TOKEN" --yes 2>&1 | tail -1)
echo "url=$url" >> "$GITHUB_OUTPUT"

- name: Promote to production
id: promote
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
run: |
vercel promote "${{ steps.deploy.outputs.url }}" \
--token "$VERCEL_TOKEN" --scope "$VERCEL_ORG_ID"
echo "url=${{ steps.deploy.outputs.url }}" >> "$GITHUB_OUTPUT"

- name: Write deployment URL to job summary
run: echo "### 🚀 Production deployed to ${{ steps.promote.outputs.url }}" >> "$GITHUB_STEP_SUMMARY"
85 changes: 85 additions & 0 deletions .github/workflows/mutation-testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Mutation Testing

on:
schedule:
# Every Sunday at 02:00 UTC
- cron: '0 2 * * 0'
workflow_dispatch:
inputs:
target:
description: 'Which target to run (all | rust | typescript)'
required: false
default: 'all'

concurrency:
group: mutation-testing
cancel-in-progress: true

jobs:
rust-mutations:
name: Rust (cargo-mutants)
if: ${{ github.event_name == 'schedule' || github.event.inputs.target == 'all' || github.event.inputs.target == 'rust' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: '1.85.0'
targets: wasm32-unknown-unknown

- uses: Swatinem/rust-cache@v2
with:
workspaces: apps/contracts

- name: Install cargo-mutants
run: cargo install cargo-mutants --locked --version 24.11.0

- name: Run cargo-mutants
working-directory: apps/contracts
run: |
cargo mutants \
--package audit_registry \
--package energy_token \
--output mutants-out \
--timeout 120 \
--jobs 2

- name: Upload mutation report
if: always()
uses: actions/upload-artifact@v4
with:
name: cargo-mutants-report
path: apps/contracts/mutants-out/
retention-days: 30

typescript-mutations:
name: TypeScript (Stryker)
if: ${{ github.event_name == 'schedule' || github.event.inputs.target == 'all' || github.event.inputs.target == 'typescript' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
with:
version: 10

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- run: pnpm install --frozen-lockfile

- name: Run Stryker
working-directory: packages/stellar
run: pnpm test:mutation

- name: Upload Stryker report
if: always()
uses: actions/upload-artifact@v4
with:
name: stryker-report
path: packages/stellar/reports/mutation/
retention-days: 30
46 changes: 46 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: E2E — Playwright Dashboard

on:
push:
branches: [main, develop, 'fix/**', 'feat/**']
pull_request:
branches: [main, develop]

jobs:
playwright:
name: Playwright E2E
runs-on: ubuntu-latest
environment: staging
timeout-minutes: 20
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- run: pnpm install --frozen-lockfile

- name: Install Playwright browsers
run: pnpm --filter web exec playwright install --with-deps chromium

- name: Run Playwright tests
run: pnpm --filter web exec playwright test
env:
CI: true
BASE_URL: ${{ vars.STAGING_URL || 'http://127.0.0.1:3000' }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
NEXT_PUBLIC_ENERGY_TOKEN_ID: ${{ secrets.NEXT_PUBLIC_ENERGY_TOKEN_ID }}
NEXT_PUBLIC_AUDIT_REGISTRY_ID: ${{ secrets.NEXT_PUBLIC_AUDIT_REGISTRY_ID }}

- name: Upload screenshots on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-screenshots
path: apps/web/test-results/
retention-days: 7
7 changes: 7 additions & 0 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ on:
types: [opened, synchronize, reopened]

jobs:
ci:
name: CI gate
uses: ./.github/workflows/ci.yml
secrets: inherit

deploy-preview:
needs: ci
runs-on: ubuntu-latest
permissions:
pull-requests: write
deployments: write
steps:
- uses: actions/checkout@v4

Expand Down
16 changes: 16 additions & 0 deletions .license-checker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"allowedLicenses": [
"MIT",
"Apache-2.0",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"CC0-1.0",
"CC-BY-3.0",
"CC-BY-4.0",
"0BSD",
"Unlicense",
"Python-2.0",
"BlueOak-1.0.0"
]
}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ solarproof/
| Level | What | Status |
|---|---|---|
| 1 | Signed meter readings + on-chain anchoring | ✅ Current |
| 2 | Hardware HSM integration (YubiKey / TPM) | 🔜 Next |
| 3 | I-REC / Energy Web / TIGR bridge | 🔮 Future |
| 2 | Hardware HSM integration (YubiKey / TPM) | ✅ Completed |
| 3 | I-REC / Energy Web / TIGR bridge | 🔜 Next |

---

Expand Down
25 changes: 25 additions & 0 deletions apps/contracts/.cargo-mutants.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# cargo-mutants configuration
# https://mutants.rs/configuration.html

# Only mutate the two critical contracts; community_governance is lower priority
packages = ["audit_registry", "energy_token"]

# Exclude generated/trivial code that doesn't need mutation coverage
exclude_globs = []

# Exclude simple getters and metadata functions that are trivially correct
exclude_re = [
"AuditRegistry::get_version",
"AuditRegistry::admin",
"AuditRegistry::api_signer",
"EnergyToken::name",
"EnergyToken::symbol",
"EnergyToken::decimals",
"EnergyToken::admin",
]

# Minimum mutation score threshold (0–100). CI fails below this.
minimum_test_coverage = 70

# Run tests in release mode for speed (Soroban SDK requires it for some features)
test_workspace = true
Loading
Loading