From 9daae1bb88dba873476080b4a897a65473851701 Mon Sep 17 00:00:00 2001 From: Big-cedar Date: Wed, 29 Jul 2026 00:12:01 +0100 Subject: [PATCH 1/2] chore(ci): add codeowners dependabot and release sbom automation --- .github/CODEOWNERS | 4 ++ .github/dependabot.yml | 29 ++++++++++++++ .github/workflows/release.yml | 71 ++++++++++++++++++++++++++++++++++ .github/workflows/smoke-ci.yml | 10 ++++- docs/CONTRIBUTING.md | 10 +++++ docs/SBOM.md | 49 +++++++++++++++++++++++ 6 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/release.yml create mode 100644 docs/SBOM.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..80806ed51 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# Security-critical contracts require code owner review from the relevant team. +/contracts/bridge/ @MettaChain/bridge +/contracts/lending/ @MettaChain/lending +/contracts/oracle/ @MettaChain/oracle diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..aabaa26ca --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,29 @@ +version: 2 +updates: + - package-ecosystem: cargo + directory: "/" + schedule: + interval: weekly + day: monday + time: "04:00" + timezone: UTC + open-pull-requests-limit: 10 + commit-message: + prefix: "chore(deps)" + labels: + - dependencies + - rust + + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + day: monday + time: "04:30" + timezone: UTC + open-pull-requests-limit: 5 + commit-message: + prefix: "chore(ci)" + labels: + - dependencies + - github-actions diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..1d5bec3b3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,71 @@ +name: Release + +on: + push: + tags: + - "v*" + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + name: Publish Release Artefacts + runs-on: ubuntu-latest + + steps: + - name: Checkout Code Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Stable Rust Toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache Cargo Dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-release- + + - name: Install Release Tooling + run: | + cargo install cargo-deny --locked + cargo install cargo-sbom --locked + + - name: Verify Dependency Policy + run: cargo deny check + + - name: Generate Workspace SBOM + run: cargo sbom --output-format spdxjson23 > propchain-sbom.json + + - name: Validate SBOM Shape + run: | + jq -e ' + .SPDXID == "SPDXRef-DOCUMENT" and + (.creationInfo.creators | length > 0) and + (.packages | length > 0) and + (.relationships | length > 0) + ' propchain-sbom.json > /dev/null + + - name: Upload SBOM Workflow Artifact + uses: actions/upload-artifact@v4 + with: + name: propchain-sbom + path: propchain-sbom.json + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: propchain-sbom.json + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/smoke-ci.yml b/.github/workflows/smoke-ci.yml index 4010891eb..36d234f05 100644 --- a/.github/workflows/smoke-ci.yml +++ b/.github/workflows/smoke-ci.yml @@ -18,6 +18,14 @@ jobs: - name: Checkout Code Repository uses: actions/checkout@v4 + - name: Validate CODEOWNERS coverage for security-critical contracts + shell: bash + run: | + test -f .github/CODEOWNERS + grep -Eq '^/contracts/bridge/\s+@MettaChain/bridge$' .github/CODEOWNERS + grep -Eq '^/contracts/lending/\s+@MettaChain/lending$' .github/CODEOWNERS + grep -Eq '^/contracts/oracle/\s+@MettaChain/oracle$' .github/CODEOWNERS + - name: Install Stable Rust Toolchain uses: dtolnay/rust-toolchain@stable with: @@ -43,4 +51,4 @@ jobs: run: cargo clippy --all-targets --all-features -- -D warnings - name: Run Core Verification Tests (test) - run: cargo test --all-features --workspace \ No newline at end of file + run: cargo test --all-features --workspace diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 4340ef057..cf2d76c47 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -6,6 +6,9 @@ rules (Settings → Branches → Add rule for `main`): - **Require a pull request before merging** — no direct pushes to `main`. +- **Require review from Code Owners** — changes under `contracts/bridge`, + `contracts/lending`, and `contracts/oracle` must be approved by the matching + owners defined in `.github/CODEOWNERS`. - **Require signed commits** — every commit on `main` must be GPG/SSH signed. - **Disallow force pushes** to `main`. - **Disallow branch deletion** for `main`. @@ -17,6 +20,13 @@ GitHub API (`PUT /repos/{owner}/{repo}/branches/main/protection`). This doc exists so the expected configuration is written down and reviewable, and so CI/README can reference a single source of truth for the policy. +The repository now tracks these security-sensitive paths in +`.github/CODEOWNERS`: + +- `contracts/bridge` +- `contracts/lending` +- `contracts/oracle` + ## Signing your commits ``` diff --git a/docs/SBOM.md b/docs/SBOM.md new file mode 100644 index 000000000..33b9788dd --- /dev/null +++ b/docs/SBOM.md @@ -0,0 +1,49 @@ +# SBOM Release Artefact + +Each tagged release publishes a `propchain-sbom.json` asset generated from the +workspace with `cargo sbom`. + +## What ships + +- **Format**: SPDX JSON 2.3 +- **Asset name**: `propchain-sbom.json` +- **Source**: the Cargo workspace rooted at this repository +- **Release hook**: `.github/workflows/release.yml` + +## What to look for + +The most useful top-level fields are: + +- `SPDXID`: confirms the document identifier. +- `creationInfo`: records when the SBOM was produced and which tool created it. +- `packages`: lists workspace crates and third-party dependencies captured from + Cargo metadata. +- `relationships`: records the dependency graph between the packages in the + document. + +## Validation + +The release workflow validates the generated artefact before upload by checking +that the document has the expected SPDX identifier plus non-empty +`creationInfo.creators`, `packages`, and `relationships` sections. + +You can reproduce the same flow locally: + +```bash +cargo install cargo-sbom --locked +cargo sbom --output-format spdxjson23 > propchain-sbom.json +jq -e ' + .SPDXID == "SPDXRef-DOCUMENT" and + (.creationInfo.creators | length > 0) and + (.packages | length > 0) and + (.relationships | length > 0) +' propchain-sbom.json > /dev/null +``` + +## How to use it + +- Review `packages` to see the exact dependency inventory captured for a + release. +- Review `relationships` to understand how a crate is pulled into the workspace. +- Pair the SBOM with `cargo deny check` and advisory scanning for compliance and + vulnerability triage. From 6a99fe27c368503afd6ea4aab0fd88da059326df Mon Sep 17 00:00:00 2001 From: Big-cedar <169001259+Cedarich@users.noreply.github.com> Date: Wed, 29 Jul 2026 00:18:48 +0100 Subject: [PATCH 2/2] chores --- contracts/lib/src/lib.rs | 10 +++++----- contracts/oracle/src/lib.rs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/contracts/lib/src/lib.rs b/contracts/lib/src/lib.rs index e8df220bc..82b7488df 100644 --- a/contracts/lib/src/lib.rs +++ b/contracts/lib/src/lib.rs @@ -4474,7 +4474,7 @@ pub mod propchain_contracts { /// Rejects the zero address (all 32 bytes == 0x00). fn ensure_not_zero_address(account: AccountId) -> Result<(), Error> { - if account == AccountId::from([0x0; 32]) { + if account == AccountId::from([0x0u8; 32]) { return Err(Error::ZeroAddress); } Ok(()) @@ -4648,7 +4648,7 @@ mod tests_pause { #[ink::test] fn test_pause_resume_flow() { let mut contract = PropertyRegistry::new(); - let _admin = AccountId::from([0x1; 32]); + let _admin = AccountId::from([0x1u8; 32]); // 1. Verify initial state assert!(!contract.get_pause_state().paused); @@ -4684,7 +4684,7 @@ mod tests_pause { // In simple unit testing here, tracking caller changes requires `ink::env::test::set_caller`. // Let's simulate a second account approval. - let account2 = AccountId::from([0x2; 32]); + let account2 = AccountId::from([0x2u8; 32]); ink::env::test::set_caller::(contract.admin()); assert!(contract.set_pause_guardian(account2, true).is_ok()); @@ -4699,7 +4699,7 @@ mod tests_pause { #[ink::test] fn test_oracle_circuit_breaker_blocks_and_resets_external_calls() { let mut contract = PropertyRegistry::new(); - let oracle = AccountId::from([0x9; 32]); + let oracle = AccountId::from([0x9u8; 32]); let metadata = PropertyMetadata { location: "Breaker Street".into(), @@ -4740,7 +4740,7 @@ mod tests_pause { #[ink::test] fn test_compliance_circuit_breaker_blocks_registration() { let mut contract = PropertyRegistry::new(); - let registry = AccountId::from([0x7; 32]); + let registry = AccountId::from([0x7u8; 32]); contract .set_compliance_registry(Some(registry)) diff --git a/contracts/oracle/src/lib.rs b/contracts/oracle/src/lib.rs index 9db158037..f4d36f783 100644 --- a/contracts/oracle/src/lib.rs +++ b/contracts/oracle/src/lib.rs @@ -1121,7 +1121,7 @@ mod propchain_oracle { let source = OracleSource { id: id.clone(), source_type: OracleSourceType::Custom, - address: AccountId::from([0x0; 32]), + address: AccountId::from([0x0u8; 32]), is_active: true, weight, last_updated: self.env().block_timestamp(), @@ -1934,7 +1934,7 @@ mod propchain_oracle { let dummy_source = OracleSource { id: source_id.clone(), source_type: OracleSourceType::Custom, - address: AccountId::from([0x0; 32]), + address: AccountId::from([0x0u8; 32]), is_active: false, weight: 0, last_updated: 0, @@ -3473,7 +3473,7 @@ mod propchain_oracle { impl Default for PropertyValuationOracle { fn default() -> Self { - Self::new(AccountId::from([0x0; 32])) + Self::new(AccountId::from([0x0u8; 32])) } } }