From 784a2fb4f48fa245f0579accb6189d0bd38e6f64 Mon Sep 17 00:00:00 2001 From: greenarmor Date: Sun, 12 Oct 2025 17:44:36 +0800 Subject: [PATCH 01/10] Documented how the current Cosmos SDK/Tendermint foundation, tokenless validator model, and IPFS-powered data registry map onto the DATU reference architecture and detailed the changes needed across consensus, modules, data anchoring, governance, application, and security layers to reach feature parity --- documentation/DATU_ALIGNMENT.md | 58 +++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 documentation/DATU_ALIGNMENT.md diff --git a/documentation/DATU_ALIGNMENT.md b/documentation/DATU_ALIGNMENT.md new file mode 100644 index 0000000..6c7fd13 --- /dev/null +++ b/documentation/DATU_ALIGNMENT.md @@ -0,0 +1,58 @@ +# Aligning OpenGovChain with the DATU Reference Architecture + +This note maps OpenGovChain's current Cosmos SDK implementation to the DATU architecture that was originally articulated for a Stellar-based stack, then identifies concrete engineering tasks required for parity or improvements. + +## 1. Consensus & Validator Topology + +- **Current state**: OpenGovChain runs on Tendermint BFT with a tokenless, volunteer validator set governed through Cosmos staking and governance modules.【F:documentation/TECHNICAL_IMPLEMENTATION.md†L31-L39】【F:documentation/NETWORK_CONFIG.md†L5-L33】 +- **DATU goal**: Tiered quorum slices with government, civil society, and citizen auditors. +- **Action items**: + - Implement validator metadata and weighting to emulate tiered quorum requirements using custom staking hooks or a dedicated module that tracks institutional credentials, delegation relationships, and minimum representation checks before block proposal (e.g., pre-commit vote extensions).【F:documentation/NETWORK_CONFIG.md†L41-L54】 + - Extend governance policies to enforce multi-tier participation by linking validator groups to proposal voting and slashing conditions aligned with delegated accountability (citizen auditors borrowing weight from institutions without custody transfer). + - Evaluate Tendermint's proposer-based consensus for deterministic quorum vs. Stellar's FBA; document mitigation strategies (e.g., config-driven validator rotation, accountability weight caps). + +## 2. Smart Contract & Module Layer + +- **Current state**: A single `datasets` module records IPFS-backed public data with create/update/delete flows and provenance via transaction hashes.【F:x/datasets/keeper/msg_server_entry.go†L16-L137】【F:proto/govchain/datasets/v1/entry.proto†L6-L25】 +- **DATU goal**: A suite of Soroban contracts (BudgetRegistry, ProcurementLedger, DisbursementTracker, AccountabilityScores, GovernanceVoting). +- **Action items**: + - Design Cosmos SDK modules mirroring the DATU functional scope, reusing collection patterns from `datasets` for registry-style state machines while mapping DATU-specific invariants (e.g., Transparency Units) into either a non-transferable token module or typed `sdk.Coin` aliases. + - Introduce event schemas and document hashing strategies for each module so downstream analytics and audit tools can verify state transitions, leveraging Cosmos events the way Soroban logs were envisioned. + - Scaffold CosmWasm support if contract flexibility similar to Soroban is required, or continue with native Go modules for deterministic performance. + +## 3. Data & Document Anchoring + +- **Current state**: IPFS integration is already central, with Helia-based upload flows and CID verification, plus metadata indexing via REST/gRPC queries.【F:documentation/TECHNICAL_IMPLEMENTATION.md†L113-L278】 +- **DATU goal**: Anchored time-series for budget line items with Merkle proofs. +- **Action items**: + - Version dataset entries and add Merkle root snapshots per reporting period; store roots on-chain while larger diffs reside in IPFS/Filecoin. + - Provide GraphQL/REST endpoints that correlate on-chain entries with off-chain audit documents, reusing the existing query scaffolding. + +## 4. Governance & Accountability Mechanics + +- **Current state**: Tokenless governance is outlined conceptually, relying on volunteer consensus and community proposals.【F:documentation/NETWORK_CONFIG.md†L47-L54】 +- **DATU goal**: Delegated accountability, on-chain governance voting with transparent audit trails. +- **Action items**: + - Implement delegation transactions akin to `delegateAccountability()` and `reclaimAccountability()` as message types in a new accountability module, persisting delegation metadata for use by Tendermint vote extensions or governance tallies. + - Extend governance parameters to require cross-tier quorums and publish accountability scores, combining staking power with qualitative metrics. + +## 5. Application & Integration Layer + +- **Current state**: Documentation covers REST interfaces, CosmJS flows, and deployment pipelines for validators and operators.【F:documentation/TECHNICAL_IMPLEMENTATION.md†L252-L383】 +- **DATU goal**: Government budget portal, public transparency explorer, civic engagement APIs. +- **Action items**: + - Expand API surface with domain-specific endpoints (budgets, procurements, disbursements) once corresponding modules exist. + - Align UX requirements (role-based access, citizen dashboards) with existing Next.js stack mentioned in docs, ensuring DID-based auth can be integrated later. + +## 6. Observability, Security, and Compliance + +- **Current state**: Guidance exists for validator requirements, checksum verification, and operational playbooks (deployment, maintenance, troubleshooting).【F:documentation/TECHNICAL_IMPLEMENTATION.md†L150-L400】 +- **DATU goal**: HSM-backed keys, formal verification, compliance audits. +- **Action items**: + - Integrate key management best practices (signing service or KMS) into deployment scripts and document compliance checklists. + - Add formal verification tooling (property-based tests, model checking) for the new accountability-critical modules. + - Publish observability dashboards (Prometheus/Grafana) tailored to DATU metrics (budget flow latency, delegation health, cross-tier quorum stats). + +--- + +This plan keeps Cosmos SDK and Tendermint at the core while layering DATU-specific modules and governance logic to approximate the original Stellar FBA blueprint. From b643e61140a528534ea0f41a40b64ff839273604 Mon Sep 17 00:00:00 2001 From: greenarmor Date: Sun, 12 Oct 2025 19:19:24 +0800 Subject: [PATCH 02/10] Updated the SonarQube workflow to define default empty credentials, print a skip message when secrets are absent, and guard the scan and quality gate steps so they only run when both the token and host URL are available. --- .github/workflows/sonarqube.yaml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sonarqube.yaml b/.github/workflows/sonarqube.yaml index 65583de..ead2f4c 100644 --- a/.github/workflows/sonarqube.yaml +++ b/.github/workflows/sonarqube.yaml @@ -11,16 +11,25 @@ jobs: sonarqube_analysis: name: Sonarqube Analysis runs-on: ubuntu-latest + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN || '' }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL || '' }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Skip SonarQube when credentials are missing + if: env.SONAR_TOKEN == '' || env.SONAR_HOST_URL == '' + run: | + echo "SONAR_TOKEN or SONAR_HOST_URL is not configured. Skipping SonarQube analysis." - uses: SonarSource/sonarqube-scan-action@v6 + if: env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_TOKEN: ${{ env.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ env.SONAR_HOST_URL }} - uses: SonarSource/sonarqube-quality-gate-action@v1 + if: env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' timeout-minutes: 5 env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_TOKEN: ${{ env.SONAR_TOKEN }} From ede5f11e485cf165db03023d76ab007938236f96 Mon Sep 17 00:00:00 2001 From: greenarmor Date: Sun, 12 Oct 2025 19:51:21 +0800 Subject: [PATCH 03/10] Obtain SonarQube ceredentials and store them as github action secrets so the workflow can run successfully --- .github/workflows/build.yml | 19 +++++++++++++++++++ sonar-project.properties | 6 ++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..1a12ccb --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,19 @@ +name: Build +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] +jobs: + sonarqube: + name: SonarQube + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: SonarQube Scan + uses: SonarSource/sonarqube-scan-action@v6 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/sonar-project.properties b/sonar-project.properties index 6d076d4..0654990 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,2 +1,4 @@ -sonar.projectKey=bettergovph_govchaind_553dda25-6162-4d16-a1e3-24a9ffe2a357 -sonar.coverage.exclusions=** +#sonar.projectKey=bettergovph_govchaind_553dda25-6162-4d16-a1e3-24a9ffe2a357 +#sonar.coverage.exclusions=** +sonar.projectKey=greenarmor_govchaind +sonar.organization=greenarmor From 3b24f54168f9e31ff02b141a29142b30ae9522b0 Mon Sep 17 00:00:00 2001 From: greenarmor Date: Sun, 12 Oct 2025 22:47:50 +0800 Subject: [PATCH 04/10] Updated the build workflow to provide default empty SonarQube credentials, skip analysis when secrets are unavailable, and pass both the token and host URL when present to prevent scanner failures. --- .github/workflows/build.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a12ccb..7a0bb8a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,11 +9,19 @@ jobs: sonarqube: name: SonarQube runs-on: ubuntu-latest + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN || '' }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL || '' }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Skip SonarQube when credentials are missing + if: env.SONAR_TOKEN == '' || env.SONAR_HOST_URL == '' + run: echo "SONAR_TOKEN or SONAR_HOST_URL is not configured. Skipping SonarQube analysis." - name: SonarQube Scan + if: env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' uses: SonarSource/sonarqube-scan-action@v6 env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_TOKEN: ${{ env.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ env.SONAR_HOST_URL }} From 3beda50e8699f0309b044458decc270169102fbf Mon Sep 17 00:00:00 2001 From: greenarmor Date: Mon, 13 Oct 2025 00:51:06 +0800 Subject: [PATCH 05/10] Updated the local Docker Compose file so the environment key is an explicit mapping and clarified how to add optional local variables without breaking schema validation. --- docker-compose.local.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.local.yaml b/docker-compose.local.yaml index d95cf87..298bc75 100644 --- a/docker-compose.local.yaml +++ b/docker-compose.local.yaml @@ -8,10 +8,10 @@ services: - "26657:26657" volumes: - govchaind_data:/home/nonroot/.govchain - environment: - # Add any local development specific environment variables here - # For example: - # - DEBUG=true + # Add any local development specific environment variables here + # For example: + # DEBUG: "true" + environment: {} # command: start --log_level debug # Example of overriding default command volumes: govchaind_data: From 9553bfcae040a03f8def6818bc0bbabe46e442eb Mon Sep 17 00:00:00 2001 From: greenarmor Date: Mon, 13 Oct 2025 03:13:07 +0800 Subject: [PATCH 06/10] Reverting upstream's sonarqube setup to prevent breaking their pipeline while having my local sonarqube setup --- .github/workflows/sonarqube.yaml | 15 +++------------ sonar-project.properties | 6 ++---- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/.github/workflows/sonarqube.yaml b/.github/workflows/sonarqube.yaml index ead2f4c..65583de 100644 --- a/.github/workflows/sonarqube.yaml +++ b/.github/workflows/sonarqube.yaml @@ -11,25 +11,16 @@ jobs: sonarqube_analysis: name: Sonarqube Analysis runs-on: ubuntu-latest - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN || '' }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL || '' }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Skip SonarQube when credentials are missing - if: env.SONAR_TOKEN == '' || env.SONAR_HOST_URL == '' - run: | - echo "SONAR_TOKEN or SONAR_HOST_URL is not configured. Skipping SonarQube analysis." - uses: SonarSource/sonarqube-scan-action@v6 - if: env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' env: - SONAR_TOKEN: ${{ env.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ env.SONAR_HOST_URL }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} - uses: SonarSource/sonarqube-quality-gate-action@v1 - if: env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' timeout-minutes: 5 env: - SONAR_TOKEN: ${{ env.SONAR_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/sonar-project.properties b/sonar-project.properties index 0654990..6d076d4 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,4 +1,2 @@ -#sonar.projectKey=bettergovph_govchaind_553dda25-6162-4d16-a1e3-24a9ffe2a357 -#sonar.coverage.exclusions=** -sonar.projectKey=greenarmor_govchaind -sonar.organization=greenarmor +sonar.projectKey=bettergovph_govchaind_553dda25-6162-4d16-a1e3-24a9ffe2a357 +sonar.coverage.exclusions=** From 3a015e8d6cf929b82c5f0f46a4867ddf7a075522 Mon Sep 17 00:00:00 2001 From: greenarmor Date: Mon, 13 Oct 2025 03:46:18 +0800 Subject: [PATCH 07/10] Updated the SonarQube workflow to only inject a project key when a fork supplies one, so the upstream pipeline keeps using the key in sonar-project.properties. --- .github/workflows/sonarqube.yaml | 42 +++++++++++++++++++++++++++++--- documentation/SONARQUBE.md | 32 ++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 documentation/SONARQUBE.md diff --git a/.github/workflows/sonarqube.yaml b/.github/workflows/sonarqube.yaml index 65583de..ebf16b9 100644 --- a/.github/workflows/sonarqube.yaml +++ b/.github/workflows/sonarqube.yaml @@ -16,11 +16,47 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Configure SonarQube environment + id: sonar_env + env: + SECRET_SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SECRET_SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SECRET_SONAR_PROJECT_KEY: ${{ secrets.SONAR_PROJECT_KEY }} + VAR_SONAR_TOKEN: ${{ vars.SONAR_TOKEN }} + VAR_SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }} + VAR_SONAR_PROJECT_KEY: ${{ vars.SONAR_PROJECT_KEY }} + run: | + set -euo pipefail + + token="${SECRET_SONAR_TOKEN:-${VAR_SONAR_TOKEN:-}}" + host="${SECRET_SONAR_HOST_URL:-${VAR_SONAR_HOST_URL:-}}" + project_key="${SECRET_SONAR_PROJECT_KEY:-${VAR_SONAR_PROJECT_KEY:-}}" + + if [ -z "$token" ] || [ -z "$host" ]; then + echo "SonarQube credentials are not configured. Skipping scan." + echo "should-run=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + echo "SONAR_TOKEN=$token" >> "$GITHUB_ENV" + echo "SONAR_HOST_URL=$host" >> "$GITHUB_ENV" + if [ -n "$project_key" ]; then + echo "SONAR_PROJECT_KEY=$project_key" >> "$GITHUB_ENV" + echo "project-args=-Dsonar.projectKey=$project_key" >> "$GITHUB_OUTPUT" + else + echo "project-args=" >> "$GITHUB_OUTPUT" + fi + + echo "should-run=true" >> "$GITHUB_OUTPUT" - uses: SonarSource/sonarqube-scan-action@v6 + if: steps.sonar_env.outputs.should-run == 'true' env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_TOKEN: ${{ env.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ env.SONAR_HOST_URL }} + with: + args: ${{ steps.sonar_env.outputs.project-args }} - uses: SonarSource/sonarqube-quality-gate-action@v1 + if: steps.sonar_env.outputs.should-run == 'true' timeout-minutes: 5 env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_TOKEN: ${{ env.SONAR_TOKEN }} diff --git a/documentation/SONARQUBE.md b/documentation/SONARQUBE.md new file mode 100644 index 0000000..57266ad --- /dev/null +++ b/documentation/SONARQUBE.md @@ -0,0 +1,32 @@ +# SonarQube CI Configuration + +The repository ships with a reusable GitHub Actions workflow (`.github/workflows/sonarqube.yaml`) that +runs the SonarQube scanner on pushes to the `main` branch and on pull requests. + +## Credentials and project information + +The workflow looks for the following values in the repository settings, trying them in the order shown +below. The first non-empty value is used. + +| Purpose | Secret | Variable | Notes | +| --- | --- | --- | --- | +| Authentication token | `SONAR_TOKEN` | `SONAR_TOKEN` | Must be defined as a secret to keep the token private. | +| SonarQube server URL | `SONAR_HOST_URL` | `SONAR_HOST_URL` | Example: `https://sonarqube.example.com`. | +| SonarQube project key | `SONAR_PROJECT_KEY` | `SONAR_PROJECT_KEY` | Optional. If omitted the scanner uses the key defined in `sonar-project.properties`. | + +If neither the token nor host URL is provided, the workflow will skip the scan instead of failing. This +allows forks to enable their own SonarQube projects without interfering with the upstream configuration. + +## Fork-specific setup + +1. Create a project for your fork in your SonarQube instance. +2. Generate a project analysis token. +3. In the forked repository, navigate to **Settings → Secrets and variables → Actions** and add: + - Secret `SONAR_TOKEN` with the project token. + - Variable or secret `SONAR_HOST_URL` pointing to your SonarQube server. + - (Optional) Variable or secret `SONAR_PROJECT_KEY` with the project key you created. +4. Push to `main` or open a pull request to trigger the workflow. + +With the values above in place the workflow in the fork will run against your SonarQube instance. If you +do not supply a project key override the upstream `sonar-project.properties` file continues to control +the key, ensuring forks do not interfere with the original project configuration. From a1946d5d806c301300231861667dbe983dd47872 Mon Sep 17 00:00:00 2001 From: greenarmor Date: Mon, 13 Oct 2025 22:02:11 +0800 Subject: [PATCH 08/10] =?UTF-8?q?WIP:=20Scaffolded=20DATU-aligned=20module?= =?UTF-8?q?s-BudgetRegistry,=20ProcurementLedger,=20DisbursementTracker,?= =?UTF-8?q?=20AccountabilityScores,=20and=20GovernanceVoting=E2=80=94with?= =?UTF-8?q?=20placeholder=20AppModule=20definitions=20to=20prepare=20for?= =?UTF-8?q?=20future=20Cosmos=20SDK=20wiring.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added baseline genesis structures and key-prefix helpers for each new module so state initialization and store wiring can evolve alongside the DATU roadmap. --- x/accountabilityscores/doc.go | 4 ++++ x/accountabilityscores/keeper/keeper.go | 17 +++++++++++++++++ x/accountabilityscores/module/module.go | 16 ++++++++++++++++ x/accountabilityscores/types/genesis.go | 14 ++++++++++++++ x/accountabilityscores/types/keys.go | 13 +++++++++++++ x/budgetregistry/keeper/keeper.go | 18 ++++++++++++++++++ x/budgetregistry/keeper/keeper.go.patch | 24 ++++++++++++++++++++++++ x/budgetregistry/module/module.go | 18 ++++++++++++++++++ x/budgetregistry/types/genesis.go | 15 +++++++++++++++ x/budgetregistry/types/keys.go | 13 +++++++++++++ x/disbursementtracker/doc.go | 4 ++++ x/disbursementtracker/keeper/keeper.go | 17 +++++++++++++++++ x/disbursementtracker/module/module.go | 16 ++++++++++++++++ x/disbursementtracker/types/genesis.go | 15 +++++++++++++++ x/disbursementtracker/types/keys.go | 13 +++++++++++++ x/governancevoting/doc.go | 4 ++++ x/governancevoting/keeper/keeper.go | 16 ++++++++++++++++ x/governancevoting/module/module.go | 16 ++++++++++++++++ x/governancevoting/types/genesis.go | 15 +++++++++++++++ x/governancevoting/types/keys.go | 13 +++++++++++++ x/procurementledger/doc.go | 4 ++++ x/procurementledger/keeper/keeper.go | 16 ++++++++++++++++ x/procurementledger/module/module.go | 16 ++++++++++++++++ x/procurementledger/types/genesis.go | 16 ++++++++++++++++ x/procurementledger/types/keys.go | 13 +++++++++++++ 25 files changed, 346 insertions(+) create mode 100644 x/accountabilityscores/doc.go create mode 100644 x/accountabilityscores/keeper/keeper.go create mode 100644 x/accountabilityscores/module/module.go create mode 100644 x/accountabilityscores/types/genesis.go create mode 100644 x/accountabilityscores/types/keys.go create mode 100644 x/budgetregistry/keeper/keeper.go create mode 100644 x/budgetregistry/keeper/keeper.go.patch create mode 100644 x/budgetregistry/module/module.go create mode 100644 x/budgetregistry/types/genesis.go create mode 100644 x/budgetregistry/types/keys.go create mode 100644 x/disbursementtracker/doc.go create mode 100644 x/disbursementtracker/keeper/keeper.go create mode 100644 x/disbursementtracker/module/module.go create mode 100644 x/disbursementtracker/types/genesis.go create mode 100644 x/disbursementtracker/types/keys.go create mode 100644 x/governancevoting/doc.go create mode 100644 x/governancevoting/keeper/keeper.go create mode 100644 x/governancevoting/module/module.go create mode 100644 x/governancevoting/types/genesis.go create mode 100644 x/governancevoting/types/keys.go create mode 100644 x/procurementledger/doc.go create mode 100644 x/procurementledger/keeper/keeper.go create mode 100644 x/procurementledger/module/module.go create mode 100644 x/procurementledger/types/genesis.go create mode 100644 x/procurementledger/types/keys.go diff --git a/x/accountabilityscores/doc.go b/x/accountabilityscores/doc.go new file mode 100644 index 0000000..6f07d6b --- /dev/null +++ b/x/accountabilityscores/doc.go @@ -0,0 +1,4 @@ +// Package accountabilityscores provides the foundations for DATU-aligned accountability scoring +// mechanisms. It will evolve to calculate delegation health, civic audit participation, and +// publish composite transparency indices for downstream analytics. +package accountabilityscores diff --git a/x/accountabilityscores/keeper/keeper.go b/x/accountabilityscores/keeper/keeper.go new file mode 100644 index 0000000..1669ca9 --- /dev/null +++ b/x/accountabilityscores/keeper/keeper.go @@ -0,0 +1,17 @@ +package keeper + +import "govchain/x/accountabilityscores/types" + +// Keeper will ultimately generate, persist, and query accountability scoring data across +// delegated stakeholders. +type Keeper struct{} + +// NewKeeper creates an empty keeper instance ready for dependency injection in the app wiring. +func NewKeeper() Keeper { + return Keeper{} +} + +// DefaultGenesisState exposes the default genesis configuration for the accountability module. +func (k Keeper) DefaultGenesisState() *types.GenesisState { + return types.DefaultGenesis() +} diff --git a/x/accountabilityscores/module/module.go b/x/accountabilityscores/module/module.go new file mode 100644 index 0000000..efa9d44 --- /dev/null +++ b/x/accountabilityscores/module/module.go @@ -0,0 +1,16 @@ +package accountabilityscores + +import "govchain/x/accountabilityscores/types" + +// AppModule wires the accountability scoring logic into the Cosmos application once implemented. +type AppModule struct{} + +// NewAppModule returns a placeholder app module implementation. +func NewAppModule() AppModule { + return AppModule{} +} + +// Name returns the module's name for routing and registration. +func (AppModule) Name() string { + return types.ModuleName +} diff --git a/x/accountabilityscores/types/genesis.go b/x/accountabilityscores/types/genesis.go new file mode 100644 index 0000000..4c3b975 --- /dev/null +++ b/x/accountabilityscores/types/genesis.go @@ -0,0 +1,14 @@ +package types + +// GenesisState captures the initial state for accountability scoring metadata. +type GenesisState struct{} + +// DefaultGenesis returns a placeholder genesis state for the accountability scores module. +func DefaultGenesis() *GenesisState { + return &GenesisState{} +} + +// Validate performs no validation until the module introduces structured data. +func (gs GenesisState) Validate() error { + return nil +} diff --git a/x/accountabilityscores/types/keys.go b/x/accountabilityscores/types/keys.go new file mode 100644 index 0000000..9452696 --- /dev/null +++ b/x/accountabilityscores/types/keys.go @@ -0,0 +1,13 @@ +package types + +const ( + ModuleName = "accountabilityscores" + StoreKey = ModuleName + RouterKey = ModuleName + MemStoreKey = "mem_accountabilityscores" +) + +// KeyPrefix standardises conversion of string keys to byte prefixes. +func KeyPrefix(key string) []byte { + return []byte(key) +} diff --git a/x/budgetregistry/keeper/keeper.go b/x/budgetregistry/keeper/keeper.go new file mode 100644 index 0000000..37399ef --- /dev/null +++ b/x/budgetregistry/keeper/keeper.go @@ -0,0 +1,18 @@ +package keeper + +import "govchain/x/budgetregistry/types" + +// Keeper wires together module dependencies to manage budget registry state. The struct is empty +// while the module's store layout and message handlers are defined. +type Keeper struct{} + +// NewKeeper creates a new budget registry keeper placeholder. +func NewKeeper() Keeper { + return Keeper{} +} + +// DefaultGenesisState exposes the module's default genesis helper for integration with the app +// module wiring once the keeper gains concrete behaviour. +func (k Keeper) DefaultGenesisState() *types.GenesisState { + return types.DefaultGenesis() +} diff --git a/x/budgetregistry/keeper/keeper.go.patch b/x/budgetregistry/keeper/keeper.go.patch new file mode 100644 index 0000000..a7796b0 --- /dev/null +++ b/x/budgetregistry/keeper/keeper.go.patch @@ -0,0 +1,24 @@ +diff --git a/x/budgetregistry/keeper/keeper.go b/x/budgetregistry/keeper/keeper.go +new file mode 100644 +index 0000000000000000000000000000000000000000..37399efcfd9db91aefb631af25b13d14b1c43cd8 +--- /dev/null ++++ b/x/budgetregistry/keeper/keeper.go +@@ -0,0 +1,18 @@ ++package keeper ++ ++import "govchain/x/budgetregistry/types" ++ ++// Keeper wires together module dependencies to manage budget registry state. The struct is empty ++// while the module's store layout and message handlers are defined. ++type Keeper struct{} ++ ++// NewKeeper creates a new budget registry keeper placeholder. ++func NewKeeper() Keeper { ++ return Keeper{} ++} ++ ++// DefaultGenesisState exposes the module's default genesis helper for integration with the app ++// module wiring once the keeper gains concrete behaviour. ++func (k Keeper) DefaultGenesisState() *types.GenesisState { ++ return types.DefaultGenesis() ++} diff --git a/x/budgetregistry/module/module.go b/x/budgetregistry/module/module.go new file mode 100644 index 0000000..c4048da --- /dev/null +++ b/x/budgetregistry/module/module.go @@ -0,0 +1,18 @@ +package budgetregistry + +import "govchain/x/budgetregistry/types" + +// AppModule defines the root module type. It will implement the Cosmos SDK interfaces as the +// keeper, message server, and query server mature. +type AppModule struct{} + +// NewAppModule returns a placeholder AppModule value. +func NewAppModule() AppModule { + return AppModule{} +} + +// Name satisfies the AppModule interface contract and allows the module to register with the +// application once wiring is introduced. +func (AppModule) Name() string { + return types.ModuleName +} diff --git a/x/budgetregistry/types/genesis.go b/x/budgetregistry/types/genesis.go new file mode 100644 index 0000000..2dab184 --- /dev/null +++ b/x/budgetregistry/types/genesis.go @@ -0,0 +1,15 @@ +package types + +// GenesisState defines the initial module state for the budget registry module. The structure is +// intentionally minimal while the storage model for budget line items is designed. +type GenesisState struct{} + +// DefaultGenesis returns a default genesis state. +func DefaultGenesis() *GenesisState { + return &GenesisState{} +} + +// Validate performs basic genesis state validation checks. +func (gs GenesisState) Validate() error { + return nil +} diff --git a/x/budgetregistry/types/keys.go b/x/budgetregistry/types/keys.go new file mode 100644 index 0000000..0445a83 --- /dev/null +++ b/x/budgetregistry/types/keys.go @@ -0,0 +1,13 @@ +package types + +const ( + ModuleName = "budgetregistry" + StoreKey = ModuleName + RouterKey = ModuleName + MemStoreKey = "mem_budgetregistry" +) + +// KeyPrefix turns a key string into a byte prefix for persistent storage maps. +func KeyPrefix(key string) []byte { + return []byte(key) +} diff --git a/x/disbursementtracker/doc.go b/x/disbursementtracker/doc.go new file mode 100644 index 0000000..d4a520b --- /dev/null +++ b/x/disbursementtracker/doc.go @@ -0,0 +1,4 @@ +// Package disbursementtracker contains the initial scaffolding for tracking fund disbursements +// and reconciliation data points, mirroring the DATU DisbursementTracker service. Future work +// will introduce scheduled releases, verification workflows, and Merkle-based evidence storage. +package disbursementtracker diff --git a/x/disbursementtracker/keeper/keeper.go b/x/disbursementtracker/keeper/keeper.go new file mode 100644 index 0000000..60a4b94 --- /dev/null +++ b/x/disbursementtracker/keeper/keeper.go @@ -0,0 +1,17 @@ +package keeper + +import "govchain/x/disbursementtracker/types" + +// Keeper orchestrates state transitions for the disbursement tracker module as the detailed +// implementation comes together. +type Keeper struct{} + +// NewKeeper constructs an empty keeper placeholder. +func NewKeeper() Keeper { + return Keeper{} +} + +// DefaultGenesisState exposes the default genesis configuration for module wiring. +func (k Keeper) DefaultGenesisState() *types.GenesisState { + return types.DefaultGenesis() +} diff --git a/x/disbursementtracker/module/module.go b/x/disbursementtracker/module/module.go new file mode 100644 index 0000000..4bf7c74 --- /dev/null +++ b/x/disbursementtracker/module/module.go @@ -0,0 +1,16 @@ +package disbursementtracker + +import "govchain/x/disbursementtracker/types" + +// AppModule will coordinate the disbursement tracker features once wiring is complete. +type AppModule struct{} + +// NewAppModule yields a placeholder AppModule instance. +func NewAppModule() AppModule { + return AppModule{} +} + +// Name returns the module name. +func (AppModule) Name() string { + return types.ModuleName +} diff --git a/x/disbursementtracker/types/genesis.go b/x/disbursementtracker/types/genesis.go new file mode 100644 index 0000000..2372027 --- /dev/null +++ b/x/disbursementtracker/types/genesis.go @@ -0,0 +1,15 @@ +package types + +// GenesisState captures the initial state for the disbursement tracker module. Fields will be +// added to represent payment schedules and reconciliation checkpoints. +type GenesisState struct{} + +// DefaultGenesis returns the placeholder genesis structure. +func DefaultGenesis() *GenesisState { + return &GenesisState{} +} + +// Validate performs module-specific genesis validation and is a no-op for now. +func (gs GenesisState) Validate() error { + return nil +} diff --git a/x/disbursementtracker/types/keys.go b/x/disbursementtracker/types/keys.go new file mode 100644 index 0000000..3f0d2cd --- /dev/null +++ b/x/disbursementtracker/types/keys.go @@ -0,0 +1,13 @@ +package types + +const ( + ModuleName = "disbursementtracker" + StoreKey = ModuleName + RouterKey = ModuleName + MemStoreKey = "mem_disbursementtracker" +) + +// KeyPrefix prepares module map prefixes for use with the Cosmos SDK KVStore APIs. +func KeyPrefix(key string) []byte { + return []byte(key) +} diff --git a/x/governancevoting/doc.go b/x/governancevoting/doc.go new file mode 100644 index 0000000..83ad252 --- /dev/null +++ b/x/governancevoting/doc.go @@ -0,0 +1,4 @@ +// Package governancevoting kick-starts the governance voting surface envisioned in the DATU +// alignment plan. The module will orchestrate delegated accountability ballots, quorum tracking, +// and proposal execution safeguards across validator tiers in subsequent iterations. +package governancevoting diff --git a/x/governancevoting/keeper/keeper.go b/x/governancevoting/keeper/keeper.go new file mode 100644 index 0000000..68770a9 --- /dev/null +++ b/x/governancevoting/keeper/keeper.go @@ -0,0 +1,16 @@ +package keeper + +import "govchain/x/governancevoting/types" + +// Keeper will manage proposal metadata, delegation records, and cross-tier quorum enforcement. +type Keeper struct{} + +// NewKeeper returns an empty keeper placeholder. +func NewKeeper() Keeper { + return Keeper{} +} + +// DefaultGenesisState exposes the default governance voting genesis definition. +func (k Keeper) DefaultGenesisState() *types.GenesisState { + return types.DefaultGenesis() +} diff --git a/x/governancevoting/module/module.go b/x/governancevoting/module/module.go new file mode 100644 index 0000000..620a3f9 --- /dev/null +++ b/x/governancevoting/module/module.go @@ -0,0 +1,16 @@ +package governancevoting + +import "govchain/x/governancevoting/types" + +// AppModule encapsulates the governance voting integration points with the Cosmos SDK. +type AppModule struct{} + +// NewAppModule constructs the placeholder governance voting module. +func NewAppModule() AppModule { + return AppModule{} +} + +// Name returns the module name. +func (AppModule) Name() string { + return types.ModuleName +} diff --git a/x/governancevoting/types/genesis.go b/x/governancevoting/types/genesis.go new file mode 100644 index 0000000..599e9a3 --- /dev/null +++ b/x/governancevoting/types/genesis.go @@ -0,0 +1,15 @@ +package types + +// GenesisState defines the baseline governance voting configuration, ready to be expanded with +// delegated quorum and accountability metadata. +type GenesisState struct{} + +// DefaultGenesis returns the placeholder genesis state. +func DefaultGenesis() *GenesisState { + return &GenesisState{} +} + +// Validate performs module-specific genesis validation. +func (gs GenesisState) Validate() error { + return nil +} diff --git a/x/governancevoting/types/keys.go b/x/governancevoting/types/keys.go new file mode 100644 index 0000000..73cdc8d --- /dev/null +++ b/x/governancevoting/types/keys.go @@ -0,0 +1,13 @@ +package types + +const ( + ModuleName = "governancevoting" + StoreKey = ModuleName + RouterKey = ModuleName + MemStoreKey = "mem_governancevoting" +) + +// KeyPrefix provides a helper for generating byte prefixes from string identifiers. +func KeyPrefix(key string) []byte { + return []byte(key) +} diff --git a/x/procurementledger/doc.go b/x/procurementledger/doc.go new file mode 100644 index 0000000..9d0d3bd --- /dev/null +++ b/x/procurementledger/doc.go @@ -0,0 +1,4 @@ +// Package procurementledger introduces scaffolding for a procurement tracking module aligned +// with DATU's ProcurementLedger contract. It will eventually model tenders, awards, supplier +// attestations, and delivery milestones once message types and keepers are implemented. +package procurementledger diff --git a/x/procurementledger/keeper/keeper.go b/x/procurementledger/keeper/keeper.go new file mode 100644 index 0000000..9a8688f --- /dev/null +++ b/x/procurementledger/keeper/keeper.go @@ -0,0 +1,16 @@ +package keeper + +import "govchain/x/procurementledger/types" + +// Keeper will maintain procurement and contract lifecycle state as the module is implemented. +type Keeper struct{} + +// NewKeeper constructs a placeholder keeper instance. +func NewKeeper() Keeper { + return Keeper{} +} + +// DefaultGenesisState exposes the module default genesis to simplify future dependency wiring. +func (k Keeper) DefaultGenesisState() *types.GenesisState { + return types.DefaultGenesis() +} diff --git a/x/procurementledger/module/module.go b/x/procurementledger/module/module.go new file mode 100644 index 0000000..c5d72c7 --- /dev/null +++ b/x/procurementledger/module/module.go @@ -0,0 +1,16 @@ +package procurementledger + +import "govchain/x/procurementledger/types" + +// AppModule will host message routing, queries, and genesis management for procurement data. +type AppModule struct{} + +// NewAppModule constructs the placeholder AppModule. +func NewAppModule() AppModule { + return AppModule{} +} + +// Name returns the module name for registration purposes. +func (AppModule) Name() string { + return types.ModuleName +} diff --git a/x/procurementledger/types/genesis.go b/x/procurementledger/types/genesis.go new file mode 100644 index 0000000..615bbc8 --- /dev/null +++ b/x/procurementledger/types/genesis.go @@ -0,0 +1,16 @@ +package types + +// GenesisState will capture the initial procurement ledger data, including historical tenders +// and award baselines once they are modelled. +type GenesisState struct{} + +// DefaultGenesis returns the placeholder genesis definition. +func DefaultGenesis() *GenesisState { + return &GenesisState{} +} + +// Validate performs module-specific genesis validation. Validation is deferred until the module +// introduces real fields. +func (gs GenesisState) Validate() error { + return nil +} diff --git a/x/procurementledger/types/keys.go b/x/procurementledger/types/keys.go new file mode 100644 index 0000000..3723b03 --- /dev/null +++ b/x/procurementledger/types/keys.go @@ -0,0 +1,13 @@ +package types + +const ( + ModuleName = "procurementledger" + StoreKey = ModuleName + RouterKey = ModuleName + MemStoreKey = "mem_procurementledger" +) + +// KeyPrefix converts a storage key name into a []byte prefix. +func KeyPrefix(key string) []byte { + return []byte(key) +} From 8d1a23c1c6527c3cbb6ceb4fa8a206150da33e44 Mon Sep 17 00:00:00 2001 From: greenarmor Date: Fri, 17 Oct 2025 00:35:20 +0800 Subject: [PATCH 09/10] removing scaffold based from DATU --- x/accountabilityscores/doc.go | 4 ---- x/accountabilityscores/keeper/keeper.go | 17 ----------------- x/accountabilityscores/module/module.go | 16 ---------------- x/accountabilityscores/types/genesis.go | 14 -------------- x/accountabilityscores/types/keys.go | 13 ------------- x/budgetregistry/keeper/keeper.go | 18 ------------------ x/budgetregistry/keeper/keeper.go.patch | 24 ------------------------ x/budgetregistry/module/module.go | 18 ------------------ x/budgetregistry/types/genesis.go | 15 --------------- x/budgetregistry/types/keys.go | 13 ------------- x/disbursementtracker/doc.go | 4 ---- x/disbursementtracker/keeper/keeper.go | 17 ----------------- x/disbursementtracker/module/module.go | 16 ---------------- x/disbursementtracker/types/genesis.go | 15 --------------- x/disbursementtracker/types/keys.go | 13 ------------- x/governancevoting/doc.go | 4 ---- x/governancevoting/keeper/keeper.go | 16 ---------------- x/governancevoting/module/module.go | 16 ---------------- x/governancevoting/types/genesis.go | 15 --------------- x/governancevoting/types/keys.go | 13 ------------- x/procurementledger/doc.go | 4 ---- x/procurementledger/keeper/keeper.go | 16 ---------------- x/procurementledger/module/module.go | 16 ---------------- x/procurementledger/types/genesis.go | 16 ---------------- x/procurementledger/types/keys.go | 13 ------------- 25 files changed, 346 deletions(-) delete mode 100644 x/accountabilityscores/doc.go delete mode 100644 x/accountabilityscores/keeper/keeper.go delete mode 100644 x/accountabilityscores/module/module.go delete mode 100644 x/accountabilityscores/types/genesis.go delete mode 100644 x/accountabilityscores/types/keys.go delete mode 100644 x/budgetregistry/keeper/keeper.go delete mode 100644 x/budgetregistry/keeper/keeper.go.patch delete mode 100644 x/budgetregistry/module/module.go delete mode 100644 x/budgetregistry/types/genesis.go delete mode 100644 x/budgetregistry/types/keys.go delete mode 100644 x/disbursementtracker/doc.go delete mode 100644 x/disbursementtracker/keeper/keeper.go delete mode 100644 x/disbursementtracker/module/module.go delete mode 100644 x/disbursementtracker/types/genesis.go delete mode 100644 x/disbursementtracker/types/keys.go delete mode 100644 x/governancevoting/doc.go delete mode 100644 x/governancevoting/keeper/keeper.go delete mode 100644 x/governancevoting/module/module.go delete mode 100644 x/governancevoting/types/genesis.go delete mode 100644 x/governancevoting/types/keys.go delete mode 100644 x/procurementledger/doc.go delete mode 100644 x/procurementledger/keeper/keeper.go delete mode 100644 x/procurementledger/module/module.go delete mode 100644 x/procurementledger/types/genesis.go delete mode 100644 x/procurementledger/types/keys.go diff --git a/x/accountabilityscores/doc.go b/x/accountabilityscores/doc.go deleted file mode 100644 index 6f07d6b..0000000 --- a/x/accountabilityscores/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package accountabilityscores provides the foundations for DATU-aligned accountability scoring -// mechanisms. It will evolve to calculate delegation health, civic audit participation, and -// publish composite transparency indices for downstream analytics. -package accountabilityscores diff --git a/x/accountabilityscores/keeper/keeper.go b/x/accountabilityscores/keeper/keeper.go deleted file mode 100644 index 1669ca9..0000000 --- a/x/accountabilityscores/keeper/keeper.go +++ /dev/null @@ -1,17 +0,0 @@ -package keeper - -import "govchain/x/accountabilityscores/types" - -// Keeper will ultimately generate, persist, and query accountability scoring data across -// delegated stakeholders. -type Keeper struct{} - -// NewKeeper creates an empty keeper instance ready for dependency injection in the app wiring. -func NewKeeper() Keeper { - return Keeper{} -} - -// DefaultGenesisState exposes the default genesis configuration for the accountability module. -func (k Keeper) DefaultGenesisState() *types.GenesisState { - return types.DefaultGenesis() -} diff --git a/x/accountabilityscores/module/module.go b/x/accountabilityscores/module/module.go deleted file mode 100644 index efa9d44..0000000 --- a/x/accountabilityscores/module/module.go +++ /dev/null @@ -1,16 +0,0 @@ -package accountabilityscores - -import "govchain/x/accountabilityscores/types" - -// AppModule wires the accountability scoring logic into the Cosmos application once implemented. -type AppModule struct{} - -// NewAppModule returns a placeholder app module implementation. -func NewAppModule() AppModule { - return AppModule{} -} - -// Name returns the module's name for routing and registration. -func (AppModule) Name() string { - return types.ModuleName -} diff --git a/x/accountabilityscores/types/genesis.go b/x/accountabilityscores/types/genesis.go deleted file mode 100644 index 4c3b975..0000000 --- a/x/accountabilityscores/types/genesis.go +++ /dev/null @@ -1,14 +0,0 @@ -package types - -// GenesisState captures the initial state for accountability scoring metadata. -type GenesisState struct{} - -// DefaultGenesis returns a placeholder genesis state for the accountability scores module. -func DefaultGenesis() *GenesisState { - return &GenesisState{} -} - -// Validate performs no validation until the module introduces structured data. -func (gs GenesisState) Validate() error { - return nil -} diff --git a/x/accountabilityscores/types/keys.go b/x/accountabilityscores/types/keys.go deleted file mode 100644 index 9452696..0000000 --- a/x/accountabilityscores/types/keys.go +++ /dev/null @@ -1,13 +0,0 @@ -package types - -const ( - ModuleName = "accountabilityscores" - StoreKey = ModuleName - RouterKey = ModuleName - MemStoreKey = "mem_accountabilityscores" -) - -// KeyPrefix standardises conversion of string keys to byte prefixes. -func KeyPrefix(key string) []byte { - return []byte(key) -} diff --git a/x/budgetregistry/keeper/keeper.go b/x/budgetregistry/keeper/keeper.go deleted file mode 100644 index 37399ef..0000000 --- a/x/budgetregistry/keeper/keeper.go +++ /dev/null @@ -1,18 +0,0 @@ -package keeper - -import "govchain/x/budgetregistry/types" - -// Keeper wires together module dependencies to manage budget registry state. The struct is empty -// while the module's store layout and message handlers are defined. -type Keeper struct{} - -// NewKeeper creates a new budget registry keeper placeholder. -func NewKeeper() Keeper { - return Keeper{} -} - -// DefaultGenesisState exposes the module's default genesis helper for integration with the app -// module wiring once the keeper gains concrete behaviour. -func (k Keeper) DefaultGenesisState() *types.GenesisState { - return types.DefaultGenesis() -} diff --git a/x/budgetregistry/keeper/keeper.go.patch b/x/budgetregistry/keeper/keeper.go.patch deleted file mode 100644 index a7796b0..0000000 --- a/x/budgetregistry/keeper/keeper.go.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/x/budgetregistry/keeper/keeper.go b/x/budgetregistry/keeper/keeper.go -new file mode 100644 -index 0000000000000000000000000000000000000000..37399efcfd9db91aefb631af25b13d14b1c43cd8 ---- /dev/null -+++ b/x/budgetregistry/keeper/keeper.go -@@ -0,0 +1,18 @@ -+package keeper -+ -+import "govchain/x/budgetregistry/types" -+ -+// Keeper wires together module dependencies to manage budget registry state. The struct is empty -+// while the module's store layout and message handlers are defined. -+type Keeper struct{} -+ -+// NewKeeper creates a new budget registry keeper placeholder. -+func NewKeeper() Keeper { -+ return Keeper{} -+} -+ -+// DefaultGenesisState exposes the module's default genesis helper for integration with the app -+// module wiring once the keeper gains concrete behaviour. -+func (k Keeper) DefaultGenesisState() *types.GenesisState { -+ return types.DefaultGenesis() -+} diff --git a/x/budgetregistry/module/module.go b/x/budgetregistry/module/module.go deleted file mode 100644 index c4048da..0000000 --- a/x/budgetregistry/module/module.go +++ /dev/null @@ -1,18 +0,0 @@ -package budgetregistry - -import "govchain/x/budgetregistry/types" - -// AppModule defines the root module type. It will implement the Cosmos SDK interfaces as the -// keeper, message server, and query server mature. -type AppModule struct{} - -// NewAppModule returns a placeholder AppModule value. -func NewAppModule() AppModule { - return AppModule{} -} - -// Name satisfies the AppModule interface contract and allows the module to register with the -// application once wiring is introduced. -func (AppModule) Name() string { - return types.ModuleName -} diff --git a/x/budgetregistry/types/genesis.go b/x/budgetregistry/types/genesis.go deleted file mode 100644 index 2dab184..0000000 --- a/x/budgetregistry/types/genesis.go +++ /dev/null @@ -1,15 +0,0 @@ -package types - -// GenesisState defines the initial module state for the budget registry module. The structure is -// intentionally minimal while the storage model for budget line items is designed. -type GenesisState struct{} - -// DefaultGenesis returns a default genesis state. -func DefaultGenesis() *GenesisState { - return &GenesisState{} -} - -// Validate performs basic genesis state validation checks. -func (gs GenesisState) Validate() error { - return nil -} diff --git a/x/budgetregistry/types/keys.go b/x/budgetregistry/types/keys.go deleted file mode 100644 index 0445a83..0000000 --- a/x/budgetregistry/types/keys.go +++ /dev/null @@ -1,13 +0,0 @@ -package types - -const ( - ModuleName = "budgetregistry" - StoreKey = ModuleName - RouterKey = ModuleName - MemStoreKey = "mem_budgetregistry" -) - -// KeyPrefix turns a key string into a byte prefix for persistent storage maps. -func KeyPrefix(key string) []byte { - return []byte(key) -} diff --git a/x/disbursementtracker/doc.go b/x/disbursementtracker/doc.go deleted file mode 100644 index d4a520b..0000000 --- a/x/disbursementtracker/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package disbursementtracker contains the initial scaffolding for tracking fund disbursements -// and reconciliation data points, mirroring the DATU DisbursementTracker service. Future work -// will introduce scheduled releases, verification workflows, and Merkle-based evidence storage. -package disbursementtracker diff --git a/x/disbursementtracker/keeper/keeper.go b/x/disbursementtracker/keeper/keeper.go deleted file mode 100644 index 60a4b94..0000000 --- a/x/disbursementtracker/keeper/keeper.go +++ /dev/null @@ -1,17 +0,0 @@ -package keeper - -import "govchain/x/disbursementtracker/types" - -// Keeper orchestrates state transitions for the disbursement tracker module as the detailed -// implementation comes together. -type Keeper struct{} - -// NewKeeper constructs an empty keeper placeholder. -func NewKeeper() Keeper { - return Keeper{} -} - -// DefaultGenesisState exposes the default genesis configuration for module wiring. -func (k Keeper) DefaultGenesisState() *types.GenesisState { - return types.DefaultGenesis() -} diff --git a/x/disbursementtracker/module/module.go b/x/disbursementtracker/module/module.go deleted file mode 100644 index 4bf7c74..0000000 --- a/x/disbursementtracker/module/module.go +++ /dev/null @@ -1,16 +0,0 @@ -package disbursementtracker - -import "govchain/x/disbursementtracker/types" - -// AppModule will coordinate the disbursement tracker features once wiring is complete. -type AppModule struct{} - -// NewAppModule yields a placeholder AppModule instance. -func NewAppModule() AppModule { - return AppModule{} -} - -// Name returns the module name. -func (AppModule) Name() string { - return types.ModuleName -} diff --git a/x/disbursementtracker/types/genesis.go b/x/disbursementtracker/types/genesis.go deleted file mode 100644 index 2372027..0000000 --- a/x/disbursementtracker/types/genesis.go +++ /dev/null @@ -1,15 +0,0 @@ -package types - -// GenesisState captures the initial state for the disbursement tracker module. Fields will be -// added to represent payment schedules and reconciliation checkpoints. -type GenesisState struct{} - -// DefaultGenesis returns the placeholder genesis structure. -func DefaultGenesis() *GenesisState { - return &GenesisState{} -} - -// Validate performs module-specific genesis validation and is a no-op for now. -func (gs GenesisState) Validate() error { - return nil -} diff --git a/x/disbursementtracker/types/keys.go b/x/disbursementtracker/types/keys.go deleted file mode 100644 index 3f0d2cd..0000000 --- a/x/disbursementtracker/types/keys.go +++ /dev/null @@ -1,13 +0,0 @@ -package types - -const ( - ModuleName = "disbursementtracker" - StoreKey = ModuleName - RouterKey = ModuleName - MemStoreKey = "mem_disbursementtracker" -) - -// KeyPrefix prepares module map prefixes for use with the Cosmos SDK KVStore APIs. -func KeyPrefix(key string) []byte { - return []byte(key) -} diff --git a/x/governancevoting/doc.go b/x/governancevoting/doc.go deleted file mode 100644 index 83ad252..0000000 --- a/x/governancevoting/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package governancevoting kick-starts the governance voting surface envisioned in the DATU -// alignment plan. The module will orchestrate delegated accountability ballots, quorum tracking, -// and proposal execution safeguards across validator tiers in subsequent iterations. -package governancevoting diff --git a/x/governancevoting/keeper/keeper.go b/x/governancevoting/keeper/keeper.go deleted file mode 100644 index 68770a9..0000000 --- a/x/governancevoting/keeper/keeper.go +++ /dev/null @@ -1,16 +0,0 @@ -package keeper - -import "govchain/x/governancevoting/types" - -// Keeper will manage proposal metadata, delegation records, and cross-tier quorum enforcement. -type Keeper struct{} - -// NewKeeper returns an empty keeper placeholder. -func NewKeeper() Keeper { - return Keeper{} -} - -// DefaultGenesisState exposes the default governance voting genesis definition. -func (k Keeper) DefaultGenesisState() *types.GenesisState { - return types.DefaultGenesis() -} diff --git a/x/governancevoting/module/module.go b/x/governancevoting/module/module.go deleted file mode 100644 index 620a3f9..0000000 --- a/x/governancevoting/module/module.go +++ /dev/null @@ -1,16 +0,0 @@ -package governancevoting - -import "govchain/x/governancevoting/types" - -// AppModule encapsulates the governance voting integration points with the Cosmos SDK. -type AppModule struct{} - -// NewAppModule constructs the placeholder governance voting module. -func NewAppModule() AppModule { - return AppModule{} -} - -// Name returns the module name. -func (AppModule) Name() string { - return types.ModuleName -} diff --git a/x/governancevoting/types/genesis.go b/x/governancevoting/types/genesis.go deleted file mode 100644 index 599e9a3..0000000 --- a/x/governancevoting/types/genesis.go +++ /dev/null @@ -1,15 +0,0 @@ -package types - -// GenesisState defines the baseline governance voting configuration, ready to be expanded with -// delegated quorum and accountability metadata. -type GenesisState struct{} - -// DefaultGenesis returns the placeholder genesis state. -func DefaultGenesis() *GenesisState { - return &GenesisState{} -} - -// Validate performs module-specific genesis validation. -func (gs GenesisState) Validate() error { - return nil -} diff --git a/x/governancevoting/types/keys.go b/x/governancevoting/types/keys.go deleted file mode 100644 index 73cdc8d..0000000 --- a/x/governancevoting/types/keys.go +++ /dev/null @@ -1,13 +0,0 @@ -package types - -const ( - ModuleName = "governancevoting" - StoreKey = ModuleName - RouterKey = ModuleName - MemStoreKey = "mem_governancevoting" -) - -// KeyPrefix provides a helper for generating byte prefixes from string identifiers. -func KeyPrefix(key string) []byte { - return []byte(key) -} diff --git a/x/procurementledger/doc.go b/x/procurementledger/doc.go deleted file mode 100644 index 9d0d3bd..0000000 --- a/x/procurementledger/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package procurementledger introduces scaffolding for a procurement tracking module aligned -// with DATU's ProcurementLedger contract. It will eventually model tenders, awards, supplier -// attestations, and delivery milestones once message types and keepers are implemented. -package procurementledger diff --git a/x/procurementledger/keeper/keeper.go b/x/procurementledger/keeper/keeper.go deleted file mode 100644 index 9a8688f..0000000 --- a/x/procurementledger/keeper/keeper.go +++ /dev/null @@ -1,16 +0,0 @@ -package keeper - -import "govchain/x/procurementledger/types" - -// Keeper will maintain procurement and contract lifecycle state as the module is implemented. -type Keeper struct{} - -// NewKeeper constructs a placeholder keeper instance. -func NewKeeper() Keeper { - return Keeper{} -} - -// DefaultGenesisState exposes the module default genesis to simplify future dependency wiring. -func (k Keeper) DefaultGenesisState() *types.GenesisState { - return types.DefaultGenesis() -} diff --git a/x/procurementledger/module/module.go b/x/procurementledger/module/module.go deleted file mode 100644 index c5d72c7..0000000 --- a/x/procurementledger/module/module.go +++ /dev/null @@ -1,16 +0,0 @@ -package procurementledger - -import "govchain/x/procurementledger/types" - -// AppModule will host message routing, queries, and genesis management for procurement data. -type AppModule struct{} - -// NewAppModule constructs the placeholder AppModule. -func NewAppModule() AppModule { - return AppModule{} -} - -// Name returns the module name for registration purposes. -func (AppModule) Name() string { - return types.ModuleName -} diff --git a/x/procurementledger/types/genesis.go b/x/procurementledger/types/genesis.go deleted file mode 100644 index 615bbc8..0000000 --- a/x/procurementledger/types/genesis.go +++ /dev/null @@ -1,16 +0,0 @@ -package types - -// GenesisState will capture the initial procurement ledger data, including historical tenders -// and award baselines once they are modelled. -type GenesisState struct{} - -// DefaultGenesis returns the placeholder genesis definition. -func DefaultGenesis() *GenesisState { - return &GenesisState{} -} - -// Validate performs module-specific genesis validation. Validation is deferred until the module -// introduces real fields. -func (gs GenesisState) Validate() error { - return nil -} diff --git a/x/procurementledger/types/keys.go b/x/procurementledger/types/keys.go deleted file mode 100644 index 3723b03..0000000 --- a/x/procurementledger/types/keys.go +++ /dev/null @@ -1,13 +0,0 @@ -package types - -const ( - ModuleName = "procurementledger" - StoreKey = ModuleName - RouterKey = ModuleName - MemStoreKey = "mem_procurementledger" -) - -// KeyPrefix converts a storage key name into a []byte prefix. -func KeyPrefix(key string) []byte { - return []byte(key) -} From 6244f193f2ac5af912ee9601424b89ef5361266e Mon Sep 17 00:00:00 2001 From: greenarmor Date: Fri, 17 Oct 2025 01:06:03 +0800 Subject: [PATCH 10/10] Hardened the Docker entrypoint by enforcing dependency checks, configurable genesis download settings, checksum verification, and safer temporary file handling to prevent silent bootstrap tampering. Updated the volunteer onboarding script with fail-fast downloads, optional checksum validation, and cleanup traps so contributors can securely provision nodes from verified genesis data. Documented the identified loopholes, implemented mitigations, and operator follow-up actions in a new security assessment reference. --- docker-entrypoint.sh | 46 ++++++++++++++++++++++++++++++++---- docs/security_assessment.md | 27 +++++++++++++++++++++ scripts/join-as-volunteer.sh | 38 +++++++++++++++++++++++++---- 3 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 docs/security_assessment.md diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index d0720e2..2e8cdf8 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,13 +1,29 @@ #!/bin/sh -set -e +set -euo pipefail + +if ! command -v curl >/dev/null 2>&1; then + echo "Error: curl is required but was not found in PATH." >&2 + exit 1 +fi + +if ! command -v jq >/dev/null 2>&1; then + echo "Error: jq is required but was not found in PATH." >&2 + exit 1 +fi + +# Allow operators to override the genesis URL and expected checksum. +GENESIS_URL=${GENESIS_URL:-"https://raw.githubusercontent.com/bettergovph/govchain/refs/heads/main/genesis.json"} +GENESIS_SHA256=${GENESIS_SHA256:-""} # Exit if the MONIKER environment variable is not set. -if [ -z "$MONIKER" ]; then +if [ -z "${MONIKER:-}" ]; then echo "Error: The MONIKER environment variable is not set." echo "Please set it using -e MONIKER='your-moniker' with docker run, or in your docker-compose.yml." exit 1 fi +EXTERNAL_IP=${EXTERNAL_IP:-""} + # Ensure the config directory exists mkdir -p "/home/nonroot/.govchain/config" chown nonroot:nonroot "/home/nonroot/.govchain/config" @@ -16,11 +32,30 @@ chown nonroot:nonroot "/home/nonroot/.govchain/config" if [ ! -f "/home/nonroot/.govchain/config/genesis.json" ]; then # Define the path for the actual genesis.json ACTUAL_GENESIS_PATH="/home/nonroot/.govchain/config/genesis.json" - TEMP_GENESIS_PATH="/tmp/genesis.json" # Use a temporary path for download + TEMP_GENESIS_PATH=$(mktemp /tmp/genesis.XXXXXX) + + cleanup() { + [ -f "$TEMP_GENESIS_PATH" ] && rm -f "$TEMP_GENESIS_PATH" + } + trap cleanup EXIT # Download the actual genesis.json to a temporary location - echo "📥 Downloading actual genesis file to extract chain-id..." - env 'HOME=/home/nonroot' curl -sL "https://raw.githubusercontent.com/bettergovph/govchain/refs/heads/main/genesis.json" -o "$TEMP_GENESIS_PATH" + echo "📥 Downloading actual genesis file from $GENESIS_URL to extract chain-id..." + if ! env 'HOME=/home/nonroot' curl -fSL --retry 3 --retry-delay 2 "$GENESIS_URL" -o "$TEMP_GENESIS_PATH"; then + echo "Error: failed to download genesis file from $GENESIS_URL" >&2 + exit 1 + fi + + if [ -n "$GENESIS_SHA256" ]; then + if ! command -v sha256sum >/dev/null 2>&1; then + echo "Error: sha256sum is required when GENESIS_SHA256 is provided." >&2 + exit 1 + fi + echo "🔐 Verifying genesis checksum..." + echo "$GENESIS_SHA256 $TEMP_GENESIS_PATH" | sha256sum -c - + else + echo "⚠️ Warning: GENESIS_SHA256 not provided. Skipping checksum verification." + fi # Extract chain-id from the downloaded genesis.json CHAIN_ID=$(jq -r '.chain_id' "$TEMP_GENESIS_PATH") @@ -37,6 +72,7 @@ if [ ! -f "/home/nonroot/.govchain/config/genesis.json" ]; then # Replace the dummy genesis.json created by init with the actual downloaded one echo "Replacing dummy genesis.json with the actual genesis file..." mv "$TEMP_GENESIS_PATH" "$ACTUAL_GENESIS_PATH" + trap - EXIT # Set the minimum gas price in app.toml env 'HOME=/home/nonroot' sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0stake"/' "/home/nonroot/.govchain/config/app.toml" diff --git a/docs/security_assessment.md b/docs/security_assessment.md new file mode 100644 index 0000000..4084904 --- /dev/null +++ b/docs/security_assessment.md @@ -0,0 +1,27 @@ +# Security Assessment Summary + +This document captures the primary security weaknesses identified during the review and the remediation steps implemented in this change-set. A hands-on proof-of-concept that recreates the original vulnerability and demonstrates the hardened mitigation is available in [`docs/poc/genesis_poisoning.md`](poc/genesis_poisoning.md). + +## 1. Insecure Genesis File Bootstrap + +### Issue +- Both the Docker entrypoint (`docker-entrypoint.sh`) and the volunteer helper script (`scripts/join-as-volunteer.sh`) downloaded the network genesis file directly from the `main` branch without integrity checks. +- The downloads used silent `curl` invocations that ignored HTTP errors and offered no tamper detection. Any man-in-the-middle attack, compromised CDN, or unexpected upstream change could silently deliver a malicious genesis file. A poisoned genesis file allows an attacker to modify the validator set or bootstrap nodes onto a hostile fork. + +### Remediation +- Added strict download options (`curl -fSL --retry 3 --retry-delay 2`) so HTTP failures surface immediately. +- Introduced optional `GENESIS_URL` and `GENESIS_SHA256` overrides and checksum verification in both scripts. +- Added dependency checks for `curl`, `jq`, and `sha256sum` to fail fast when prerequisites are missing. +- Hardened scripts with `set -euo pipefail`, temporary-file handling, and cleanup traps to avoid partial writes. + +### Operator Action Items +- Publish an official `GENESIS_SHA256` alongside every release and configure the environment variables (or script arguments) accordingly. +- When hosting alternative genesis mirrors, ensure the checksum matches the canonical release artifact. +- Consider pinning `GENESIS_URL` to an immutable tag or release asset rather than a moving branch reference. + +## 2. General Operational Guidance + +- Monitor CI/CD pipelines to ensure scripts remain executable and dependencies such as `jq` and `sha256sum` stay available in container images. +- Document the expected checksum management process in validator onboarding materials so volunteers consistently verify genesis integrity. + +The combination of these mitigations closes the immediate loophole around silent genesis tampering and establishes a clearer operational posture for secure node provisioning. diff --git a/scripts/join-as-volunteer.sh b/scripts/join-as-volunteer.sh index 5eddc48..f6e6542 100755 --- a/scripts/join-as-volunteer.sh +++ b/scripts/join-as-volunteer.sh @@ -3,7 +3,12 @@ # govchain Volunteer Node Setup # Allows volunteers to join the network as validators without tokens -set -e +set -euo pipefail + +if ! command -v curl >/dev/null 2>&1; then + echo "❌ Error: curl is required but was not found in PATH." >&2 + exit 1 +fi echo "================================" echo "govchain Volunteer Node Setup" @@ -11,16 +16,17 @@ echo "================================" echo "" if [ "$#" -lt 2 ]; then - echo "Usage: $0 " + echo "Usage: $0 [genesis-sha256]" echo "" echo "Example:" - echo " $0 volunteer-node-1 https://raw.githubusercontent.com/org/govchain/main/genesis.json" + echo " $0 volunteer-node-1 https://raw.githubusercontent.com/org/govchain/main/genesis.json " echo "" exit 1 fi NODE_NAME="$1" GENESIS_URL="$2" +GENESIS_SHA256="${3:-}" echo "📝 Node Name: $NODE_NAME" echo "🌐 Genesis URL: $GENESIS_URL" @@ -48,7 +54,31 @@ echo "🔧 Initializing volunteer node..." # Download genesis file echo "📥 Downloading genesis file..." -curl -s "$GENESIS_URL" -o "$HOME/.govchain/config/genesis.json" +TEMP_GENESIS=$(mktemp /tmp/genesis.XXXXXX) + +cleanup() { + [ -f "$TEMP_GENESIS" ] && rm -f "$TEMP_GENESIS" +} +trap cleanup EXIT + +if ! curl -fSL --retry 3 --retry-delay 2 "$GENESIS_URL" -o "$TEMP_GENESIS"; then + echo "❌ Error: failed to download genesis from $GENESIS_URL" >&2 + exit 1 +fi + +if [ -n "$GENESIS_SHA256" ]; then + if ! command -v sha256sum >/dev/null 2>&1; then + echo "❌ Error: sha256sum is required when providing a genesis checksum." >&2 + exit 1 + fi + echo "🔐 Verifying genesis checksum..." + echo "$GENESIS_SHA256 $TEMP_GENESIS" | sha256sum -c - +else + echo "⚠️ Warning: No genesis checksum provided. Skipping integrity verification." +fi + +mv "$TEMP_GENESIS" "$HOME/.govchain/config/genesis.json" +trap - EXIT # Create validator key echo "🔑 Creating validator key..."