diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd5590b --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +node_modules/ +.npmrc +.env +.env.* +__tests__/ +coverage/ +.nyc_output/ +dist/ +build/ +.cache/ +*.log +.DS_Store +tmp/ +.tmp/ +__pycache__/ +*.pyc +.venv/ +venv/ +*.egg-info/ +.pytest_cache/ +READY_TO_PUBLISH diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d1da2a9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,25 @@ +# GridGuard Agents and Architecture + +Overview +- GridGuard uses a modular agent-based architecture to enable secure, attested cross-domain optimization. +- Agents (represented in code as AttestedAgent) are hardware-backed with remote attestation scaffolding and per-agent credentials tied to access contracts. +- The system orchestrates across modules: Security Contracts Registry, Verifiable Optimization, Transport, Governance Ledger, Delta-Sync, Adapters Marketplace, and a Simulation Harness. + +Tech Stack (Python, MVP): +- Core language: Python 3.8+ +- Dependencies are minimal; tests use pytest. +- Crypto-like primitives are simulated for MVP: signatures via SHA-256 digests; ZK-proof stubs emulate verification pipelines. + +Testing and Verification Commands +- Run tests: bash test.sh +- Inspect modules: pytest -q tests/test_basic.py +- Lint (optional): flake8 (if configured in the environment) + +Repository Rules +- Do not modify the public API in breaking ways without updating tests. +- Each feature is implemented as a small, testable unit under src/gridguard_secure_attested_cross_domain_e. +- The MVP is designed to be extended by other agents and adapters in subsequent sprint phases. + +Contributing +- Implement new adapters by adding entries to AdaptersMarketplace and exposing simple interfaces for attestation and policy enforcement. +- Extend Verifiable Optimization with more realistic ZK-proofs and privacy-preserving computations in future iterations. diff --git a/README.md b/README.md index 9a5f858..5888c51 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,32 @@ -# gridguard-secure-attested-cross-domain-e +# GridGuard: Secure, Attested Cross-Domain Energy Mesh Orchestrator (MVP) -Problem: Utilities and communities want to optimize cross-domain energy systems (electricity, water pumping, heating) with strong security guarantees, verifiable data integrity, and auditable governance. Current open platforms focus on optimization b \ No newline at end of file +GridGuard provides a security-first framework overlaying cross-domain optimization stacks (e.g., CatOpt/Open-EnergyMesh). +This MVP implements a minimal, testable subset to demonstrate architecture, governance, attestation, and verifiable optimization hooks. + +What’s included in this MVP: +- Security Contracts Registry: versioned contracts describing data-exposure rules and attestation policies. +- Verifiable Optimization: a local solver with a stub for a zero-knowledge proof that demonstrates verifiability without exposing raw data. +- Attested Agents: simple hardware-backed attestation scaffolding with a credential associated to each agent. +- Secure Transport: basic channel abstraction with key rotation stubs. +- Tamper-Evident Governance Ledger: append-only log with signatures and optional public anchoring (simulated). +- Delta-Sync: state reconciliation with proof checks. +- Adapters Marketplace: registry for pre-vetted adapters and their metadata. +- Simulation Harness: lightweight digital twin scaffolding for validation. + +Project Structure (Python): +- src/gridguard_secure_attested_cross_domain_e/ + - contracts.py + - optimization.py + - attestation.py + - transport.py + - governance.py + - marketplace.py + - simulation.py + - __init__.py + +Tests: tests/test_basic.py + +How to run tests: + bash test.sh + +This README also serves as a marketing and onboarding document to explain the architecture and how to contribute. diff --git a/gridguard_secure_attested_cross_domain_e/attestation.py b/gridguard_secure_attested_cross_domain_e/attestation.py new file mode 100644 index 0000000..4eb96ce --- /dev/null +++ b/gridguard_secure_attested_cross_domain_e/attestation.py @@ -0,0 +1,3 @@ +from src.gridguard_secure_attested_cross_domain_e.attestation import AttestedAgent + +__all__ = ["AttestedAgent"] diff --git a/gridguard_secure_attested_cross_domain_e/contracts.py b/gridguard_secure_attested_cross_domain_e/contracts.py new file mode 100644 index 0000000..fc1fab8 --- /dev/null +++ b/gridguard_secure_attested_cross_domain_e/contracts.py @@ -0,0 +1,3 @@ +from src.gridguard_secure_attested_cross_domain_e.contracts import SecurityContractsRegistry + +__all__ = ["SecurityContractsRegistry"] diff --git a/gridguard_secure_attested_cross_domain_e/governance.py b/gridguard_secure_attested_cross_domain_e/governance.py new file mode 100644 index 0000000..0ac612d --- /dev/null +++ b/gridguard_secure_attested_cross_domain_e/governance.py @@ -0,0 +1,3 @@ +from src.gridguard_secure_attested_cross_domain_e.governance import GovernanceLedger, DeltaSync + +__all__ = ["GovernanceLedger", "DeltaSync"] diff --git a/gridguard_secure_attested_cross_domain_e/marketplace.py b/gridguard_secure_attested_cross_domain_e/marketplace.py new file mode 100644 index 0000000..c2d9231 --- /dev/null +++ b/gridguard_secure_attested_cross_domain_e/marketplace.py @@ -0,0 +1,3 @@ +from src.gridguard_secure_attested_cross_domain_e.marketplace import AdaptersMarketplace + +__all__ = ["AdaptersMarketplace"] diff --git a/gridguard_secure_attested_cross_domain_e/optimization.py b/gridguard_secure_attested_cross_domain_e/optimization.py new file mode 100644 index 0000000..862ead5 --- /dev/null +++ b/gridguard_secure_attested_cross_domain_e/optimization.py @@ -0,0 +1,3 @@ +from src.gridguard_secure_attested_cross_domain_e.optimization import VerifiableOptimization + +__all__ = ["VerifiableOptimization"] diff --git a/gridguard_secure_attested_cross_domain_e/simulation.py b/gridguard_secure_attested_cross_domain_e/simulation.py new file mode 100644 index 0000000..f203bf2 --- /dev/null +++ b/gridguard_secure_attested_cross_domain_e/simulation.py @@ -0,0 +1,3 @@ +from src.gridguard_secure_attested_cross_domain_e.simulation import SimulationHarness + +__all__ = ["SimulationHarness"] diff --git a/gridguard_secure_attested_cross_domain_e/transport.py b/gridguard_secure_attested_cross_domain_e/transport.py new file mode 100644 index 0000000..e315641 --- /dev/null +++ b/gridguard_secure_attested_cross_domain_e/transport.py @@ -0,0 +1,3 @@ +from src.gridguard_secure_attested_cross_domain_e.transport import TransportLayer + +__all__ = ["TransportLayer"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e9b49d7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,20 @@ +[build-system] +requires = ["setuptools>=61", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "gridguard_secure_attested_cross_domain_e" +version = "0.0.1" +description = "Security-first cross-domain energy optimization with attestation and verifiable governance" +readme = "README.md" +requires-python = ">=3.8" +license = {text = "MIT"} +authors = [{name = "OpenCode SWARM"}] +keywords = ["security", "attestation", "cross-domain", "energy"] + +[project.urls] +Homepage = "https://example.org/gridguard" + +[tool.setuptools] +package-dir = { "" = "src" } +packages = ["gridguard_secure_attested_cross_domain_e"] diff --git a/src/gridguard_secure_attested_cross_domain_e/__init__.py b/src/gridguard_secure_attested_cross_domain_e/__init__.py new file mode 100644 index 0000000..1b06519 --- /dev/null +++ b/src/gridguard_secure_attested_cross_domain_e/__init__.py @@ -0,0 +1,24 @@ +"""Public package interface for gridguard_secure_attested_cross_domain_e MVP. + +This file re-exports core components for convenient imports during testing +and exploration. The true implementations live in their respective modules. +""" + +from .contracts import SecurityContractsRegistry +from .optimization import VerifiableOptimization +from .attestation import AttestedAgent +from .transport import TransportLayer +from .governance import GovernanceLedger, DeltaSync +from .marketplace import AdaptersMarketplace +from .simulation import SimulationHarness + +__all__ = [ + "SecurityContractsRegistry", + "VerifiableOptimization", + "AttestedAgent", + "TransportLayer", + "GovernanceLedger", + "DeltaSync", + "AdaptersMarketplace", + "SimulationHarness", +] diff --git a/src/gridguard_secure_attested_cross_domain_e/attestation.py b/src/gridguard_secure_attested_cross_domain_e/attestation.py new file mode 100644 index 0000000..9acedba --- /dev/null +++ b/src/gridguard_secure_attested_cross_domain_e/attestation.py @@ -0,0 +1,23 @@ +from typing import Optional + + +class AttestedAgent: + """A lightweight attested agent scaffold. + + Each agent has an id and a hardware class. Attestation generates a credential that + would be used to enforce contract permissions in a real deployment. + """ + + def __init__(self, agent_id: str, hardware: str = "TEE"): # pragma: no cover - trivial + self.agent_id = agent_id + self.hardware = hardware + self._credential: Optional[str] = None + + def attest(self) -> bool: + # In a real system, remote attestation would happen here. + self._credential = f"attest-{self.agent_id}-{self.hardware}-v1" + return True + + @property + def credential(self) -> Optional[str]: + return self._credential diff --git a/src/gridguard_secure_attested_cross_domain_e/contracts.py b/src/gridguard_secure_attested_cross_domain_e/contracts.py new file mode 100644 index 0000000..a6827b3 --- /dev/null +++ b/src/gridguard_secure_attested_cross_domain_e/contracts.py @@ -0,0 +1,17 @@ +from typing import Any, Dict + + +class SecurityContractsRegistry: + """Simple in-memory security contracts registry. + + Stores versioned contracts that describe data-exposure rules and attestation policies. + """ + + def __init__(self) -> None: + self._contracts: Dict[str, Dict[str, Any]] = {} + + def register_contract(self, version: str, contract: Dict[str, Any]) -> None: + self._contracts[version] = contract + + def get_contract(self, version: str) -> Dict[str, Any]: + return self._contracts.get(version, {}) diff --git a/src/gridguard_secure_attested_cross_domain_e/governance.py b/src/gridguard_secure_attested_cross_domain_e/governance.py new file mode 100644 index 0000000..84b8bbe --- /dev/null +++ b/src/gridguard_secure_attested_cross_domain_e/governance.py @@ -0,0 +1,36 @@ +import hashlib +import time +from typing import Any, Dict, List + + +class GovernanceLedger: + """Append-only governance log with simplistic cryptographic signatures.""" + + def __init__(self) -> None: + self._events: List[Dict[str, Any]] = [] + + def _sign(self, event: Dict[str, Any]) -> str: + payload = f"{event}{time.time()}".encode() + return hashlib.sha256(payload).hexdigest() + + def append_event(self, event: Dict[str, Any]) -> Dict[str, Any]: + entry = dict(event) + entry["signature"] = self._sign(entry) + self._events.append(entry) + return entry + + def get_events(self) -> List[Dict[str, Any]]: + return list(self._events) + + +class DeltaSync: + """Tiny delta-sync helper that validates a proof and merges states.""" + + @staticmethod + def reconcile(local_state: Dict[str, Any], remote_state: Dict[str, Any], proof: Dict[str, Any]) -> Dict[str, Any]: + if not proof or not proof.get("valid", False): + # In real systems, you'd raise or handle conflicts; here we prefer local state + return dict(local_state) + merged = dict(local_state) + merged.update(remote_state) + return merged diff --git a/src/gridguard_secure_attested_cross_domain_e/marketplace.py b/src/gridguard_secure_attested_cross_domain_e/marketplace.py new file mode 100644 index 0000000..ae52d24 --- /dev/null +++ b/src/gridguard_secure_attested_cross_domain_e/marketplace.py @@ -0,0 +1,17 @@ +from typing import Any, Dict, List + + +class AdaptersMarketplace: + """Simple adapter registry for security modules.""" + + def __init__(self) -> None: + self._adapters: Dict[str, Dict[str, Any]] = {} + + def register_adapter(self, name: str, info: Dict[str, Any]) -> None: + self._adapters[name] = dict(info, name=name) + + def list_adapters(self) -> List[Dict[str, Any]]: + return list(self._adapters.values()) + + def get_adapter(self, name: str) -> Dict[str, Any]: + return self._adapters.get(name, {}) diff --git a/src/gridguard_secure_attested_cross_domain_e/optimization.py b/src/gridguard_secure_attested_cross_domain_e/optimization.py new file mode 100644 index 0000000..fd7a41a --- /dev/null +++ b/src/gridguard_secure_attested_cross_domain_e/optimization.py @@ -0,0 +1,20 @@ +from typing import Any, Dict, Tuple + + +class VerifiableOptimization: + """Tiny verifiable-optimization prototype with a ZK-proof stub. + + The real system would run a solver and produce a succinct zero-knowledge proof. + Here we return a simple solution and a mock proof string for testing integration. + """ + + @staticmethod + def run_local_solver(objective: Dict[str, Any], constraints: Dict[str, Any], seed: int = 0) -> Tuple[Dict[str, Any], str]: + # Minimal deterministic placeholder solution + solution = {k: v for k, v in (objective or {}).items()} + # Ensure at least one key to demonstrate non-empty result + if not solution: + solution = {"x": 0} + # Mock proof that changes with seed to look different across runs + proof = f"ZK_PROOF_SEED_{seed}" + return solution, proof diff --git a/src/gridguard_secure_attested_cross_domain_e/simulation.py b/src/gridguard_secure_attested_cross_domain_e/simulation.py new file mode 100644 index 0000000..f1b6893 --- /dev/null +++ b/src/gridguard_secure_attested_cross_domain_e/simulation.py @@ -0,0 +1,13 @@ +from typing import Any, Dict + + +class SimulationHarness: + """Tiny simulation harness to validate security properties in a controlled way.""" + + @staticmethod + def simulate(district_config: Dict[str, Any]) -> Dict[str, Any]: + # Minimal echo of the district config with a simple state machine placeholder + return { + "district_config": district_config, + "state": "initialized", + } diff --git a/src/gridguard_secure_attested_cross_domain_e/transport.py b/src/gridguard_secure_attested_cross_domain_e/transport.py new file mode 100644 index 0000000..1df1192 --- /dev/null +++ b/src/gridguard_secure_attested_cross_domain_e/transport.py @@ -0,0 +1,22 @@ +from typing import Any + + +class TransportLayer: + """Minimal transport abstraction with key rotation and mutual authentication stubs.""" + + def __init__(self): + self._peer_keys = {} + self._current_key = "INITIAL_KEY" + + def create_channel(self, peer: str) -> dict: + # Return a minimal channel descriptor; represents a secured channel in MVP + chan = { + "peer": peer, + "key": self._current_key, + "status": "established", + } + self._peer_keys[peer] = self._current_key + return chan + + def rotate_keys(self) -> None: + self._current_key = f"KEY_{hash(self._current_key) & 0xFFFFFFFF}" diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..30fac23 --- /dev/null +++ b/test.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Running pytest..." +pytest -q + +echo "Building package..." +python3 -m build + +echo "All tests and build succeeded." diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..b1da5b2 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,8 @@ +import sys +import os + +# Ensure the src/ directory is on PYTHONPATH so tests can import the package +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +SRC = os.path.join(ROOT, "src") +if SRC not in sys.path: + sys.path.insert(0, SRC) diff --git a/tests/test_basic.py b/tests/test_basic.py new file mode 100644 index 0000000..0886df2 --- /dev/null +++ b/tests/test_basic.py @@ -0,0 +1,54 @@ +import pytest + +from gridguard_secure_attested_cross_domain_e.contracts import SecurityContractsRegistry +from gridguard_secure_attested_cross_domain_e.optimization import VerifiableOptimization +from gridguard_secure_attested_cross_domain_e.attestation import AttestedAgent +from gridguard_secure_attested_cross_domain_e.governance import GovernanceLedger, DeltaSync +from gridguard_secure_attested_cross_domain_e.transport import TransportLayer +from gridguard_secure_attested_cross_domain_e.marketplace import AdaptersMarketplace +from gridguard_secure_attested_cross_domain_e.simulation import SimulationHarness + + +def test_security_contract_registry(): + reg = SecurityContractsRegistry() + reg.register_contract("v1", {"policy": "no_raw_data"}) + assert reg.get_contract("v1")["policy"] == "no_raw_data" + + +def test_verifiable_optimization(): + obj = {"x": 10, "y": 5} + constr = {"limit": 20} + sol, proof = VerifiableOptimization.run_local_solver(obj, constr, seed=7) + assert isinstance(sol, dict) + assert isinstance(proof, str) and proof.startswith("ZK_PROOF_") + + +def test_attested_agent(): + agent = AttestedAgent("agent-1") + ok = agent.attest() + assert ok is True + assert agent.credential is not None + + +def test_governance_ledger_and_delta_sync(): + ledger = GovernanceLedger() + event = {"action": "deploy", "agent": "agent-1"} + entry = ledger.append_event(event) + assert "signature" in entry + # DeltaSync + local = {"budget": 100} + remote = {"budget": 95} + reconciled = DeltaSync.reconcile(local, remote, {"valid": True}) + assert reconciled["budget"] == 95 + + +def test_adapters_marketplace(): + market = AdaptersMarketplace() + market.register_adapter("attestation-adapter", {"type": "attestation", "version": "1.0"}) + adapters = market.list_adapters() + assert any(a["name"] == "attestation-adapter" for a in adapters) or adapters + + +def test_simulation_harness(): + sim = SimulationHarness.simulate({"grid": "test"}) + assert sim["state"] == "initialized"