Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/ossf-scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright the Hyperledger Fabric contributors. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

name: Scorecard

on:
branch_protection_rule: {} # re-evaluate if branch protection rules change
push:
branches: [main]
schedule:
- cron: '23 6 1,16 * *' # 1st and 16th of each month at 06:23 UTC — keeps the badge fresh
workflow_dispatch: {} # allows manually triggering the first run

permissions: read-all

jobs:
scorecard:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
security-events: write # Upload SARIF to code scanning
id-token: write # OIDC: required for publish_results

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Run Scorecard analysis
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
with:
results_file: results.sarif
results_format: sarif
repo_token: ${{ secrets.GITHUB_TOKEN }}
publish_results: true # publishes the badge results

- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@1190a975f95ce23525efb6a3fc21ea29567c1b52 # v3
with:
sarif_file: results.sarif
39 changes: 38 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,48 @@ jobs:
- name: Install build dependencies
run: |
python -m pip install --upgrade pip
python -m pip install build setuptools wheel
python -m pip install build twine packaging

- name: Build distribution
run: python -m build --sdist --wheel

- name: Check metadata
run: python -m twine check dist/*

- name: Verify tag matches package version
if: startsWith(github.ref, 'refs/tags/')
run: |
python - <<'PY'
import glob
import os
import zipfile
from packaging.version import Version

tag = os.environ["GITHUB_REF_NAME"]
if not tag.startswith("v"):
raise SystemExit(f"Unexpected tag (must start with 'v'): {tag}")

wheels = glob.glob("dist/*.whl")
if not wheels:
raise SystemExit("No wheel found in dist/")

with zipfile.ZipFile(wheels[0]) as zf:
meta = next(n for n in zf.namelist() if n.endswith(".dist-info/METADATA"))
version = None
for line in zf.read(meta).decode().splitlines():
if line.startswith("Version:"):
version = line.split(":", 1)[1].strip()
break
if version is None:
raise SystemExit("METADATA without version")

print(f"Git tag: {tag}")
print(f"Package version: {version}")
if Version(tag.removeprefix("v")) != Version(version):
raise SystemExit(f"::error::Version mismatch: tag={tag}, package={version}")
print("OK: tag and version match")
PY

# Trusted Publishing: no password required. The action obtains an ephemeral
# OIDC token signed by GitHub, which PyPI validates against the
# registered publisher. There are no secrets to rotate or leak.
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt -r requirements-dev.txt
python -m pip install -e .
- name: Run tests
run: python -m pytest -q

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![GitHub License](https://img.shields.io/github/license/hyperledger/fabric-chaincode-python)
[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/14928/badge)](https://bestpractices.coreinfrastructure.org/projects/14928)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/hyperledger/fabric-chaincode-python/badge)](https://scorecard.dev/viewer/?uri=github.com/hyperledger/fabric-chaincode-python)
[![OpenSSF Scorecard](https://github.com/hyperledger/fabric-chaincode-python/actions/workflows/CI.yml/badge.svg)](https://scorecard.dev/viewer/?uri=github.com/hyperledger/fabric-chaincode-python)

[![Python Version](https://img.shields.io/pypi/pyversions/fabric-chaincode-python.svg)](https://pypi.org/project/fabric-chaincode-python/)
[![GitHub Actions](https://github.com/hyperledger/fabric-chaincode-python/workflows/CI/badge.svg)](https://github.com/hyperledger/fabric-chaincode-python/actions?query=workflow%3ACI)
Expand Down
2 changes: 1 addition & 1 deletion RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Artifacts are available in GitHub Actions run details:

```bash
pip install dist/fabric-chaincode-python-*.whl
python -c "import src.fabric_shim; print('✓ Package imported successfully')"
python -c "import fabric_chaincode_python; print('✓ Package imported successfully')"
```

## PyPI Publishing (Optional)
Expand Down
4 changes: 2 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@

- [ ] Legacy chaincode mode (optional)
- [ ] Complete documentation
- [ ] Publish to PyPI
- [x] Publish to PyPI

## Q1-Q2 2027

- [ ] Community adoption
- [ ] Migration to official project (if applicable)
- [x] Migration to official project (if applicable)
20 changes: 11 additions & 9 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ asset-transfer-sbe) so you can compare implementations side-by-side.
2. **Read**: each example has its own `README.md` with the full
packaging / install / approve / commit / run / invoke / query
sequence.
3. **Run**: from the repository root,
```bash
pip install -r requirements.txt
export CHAINCODE_ID="<package_id>"
export CHAINCODE_SERVER_ADDRESS="127.0.0.1:9999"
python examples/ccaas/<layer>/<scenario>/main.py
```
3. **Run**: from the repository root — create/activate a virtualenv and install dependencies, then start the example:
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
export CHAINCODE_ID="<package_id>"
export CHAINCODE_SERVER_ADDRESS="127.0.0.1:9999"
./.venv/bin/python examples/ccaas/<layer>/<scenario>/main.py
```

## What is CCAAS?

Expand All @@ -78,8 +80,8 @@ for more details on the CCAAS architecture.

## Related Documentation

- [`fabric_shim` package](../src/fabric_shim/) — low-level chaincode shim.
- [`fabric_contract_api` package](../src/fabric_contract_api/) — high-level
- [`fabric_shim` package](../src/fabric_chaincode_python/fabric_shim/) — low-level chaincode shim.
- [`fabric_contract_api` package](../src/fabric_chaincode_python/fabric_contract_api/) — high-level
contract API (Python port of `fabric-contract-api-go`).
- [Hyperledger Fabric Official Docs](https://hyperledger-fabric.readthedocs.io/)
- [CCAAS Architecture](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html)
Expand Down
6 changes: 3 additions & 3 deletions examples/STRUCTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ swap:

- Single self-contained file.
- Resolves the repository root at runtime by walking up the parent
chain looking for `src/fabric_shim` (or `src/fabric_contract_api`).
chain looking for `src/fabric_chaincode_python/fabric_shim` (or `src/fabric_chaincode_python/fabric_contract_api`).
This makes the example runnable from any working directory.
- Exposes a `build_chaincode()` factory (used by tests) and a `main()`
entry point.
Expand Down Expand Up @@ -153,8 +153,8 @@ Each README follows this template:

Each example:

- References the parent `src/fabric_shim/` and / or
`src/fabric_contract_api/` for the framework.
- References the parent `src/fabric_chaincode_python/fabric_shim/` and / or
`src/fabric_chaincode_python/fabric_contract_api/` for the framework.
- Uses the parent `requirements.txt` or specifies its own subset.
- Operates independently once deployed — the chaincode process does not
need the source tree at runtime as long as `PYTHONPATH=/app` is set
Expand Down
4 changes: 3 additions & 1 deletion examples/ccaas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ style you prefer:
2. **Pick a scenario**: `asset-transfer-basic/` (CRUD) or
`asset-transfer-sbe/` (with transfer).
3. **Open the example's `README.md`** — it has the full packaging,
install, approve, commit, run, invoke, and query sequence.
install, approve, commit, run, invoke, and query sequence. When running
examples locally prefer the repository virtualenv and invoke the
example with `./.venv/bin/python`.

## Common prerequisites

Expand Down
14 changes: 7 additions & 7 deletions examples/ccaas/fabric-contract-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
These examples use the high-level **`fabric_contract_api`** package,
which is the Python equivalent of Go's
[`fabric-contract-api-go`](https://github.com/hyperledger/fabric-contract-api-go).
You subclass [`Contract`](../../../src/fabric_contract_api/contractapi/contract.py)
You subclass [`Contract`](../../../src/fabric_chaincode_python/fabric_contract_api/contractapi/contract.py)
and declare each transaction as a public async method — the framework
handles dispatch, argument conversion, metadata generation, and
schema validation automatically.
Expand Down Expand Up @@ -47,12 +47,12 @@ examples:
2. Build the CCAAS package using the example's `connection.json` /
`metadata.json`.
3. `peer lifecycle chaincode install / approveformyorg / commit`.
4. Start the chaincode process:
```bash
export CHAINCODE_ID="<package_id>"
export CHAINCODE_SERVER_ADDRESS="127.0.0.1:9999"
python examples/ccaas/fabric-contract-api/<example-name>/main.py
```
4. Start the chaincode process (from the repository root, using the project's virtualenv):
```bash
export CHAINCODE_ID="<package_id>"
export CHAINCODE_SERVER_ADDRESS="127.0.0.1:9999"
./.venv/bin/python examples/ccaas/fabric-contract-api/<example-name>/main.py
```
5. `peer chaincode invoke` / `query` against the running chaincode —
including the metadata query:
```bash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,5 @@ examples/ccaas/fabric-contract-api/asset-transfer-basic/
## References

- [fabric-shim version of this sample](../../fabric-shim/asset-transfer-basic/)
- [fabric_contract_api documentation](../../../src/fabric_contract_api/README.md)
- [fabric_contract_api documentation](../../../../src/fabric_chaincode_python/fabric_contract_api/README.md)
- [Hyperledger Fabric Chaincode as a Service](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html)
19 changes: 1 addition & 18 deletions examples/ccaas/fabric-contract-api/asset-transfer-basic/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,10 @@
from __future__ import annotations

import json
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import List, Optional

# Make sure the repository root is on ``sys.path`` so that the
# ``src.fabric_contract_api`` packages can be imported when the file is
# run directly. Walk up the parent chain looking for the directory that
# contains ``src/``.
_HERE = Path(__file__).resolve().parent
REPO_ROOT = None
for parent in [_HERE, *_HERE.parents]:
if (parent / "src" / "fabric_contract_api").is_dir():
REPO_ROOT = parent
break
if REPO_ROOT is None:
REPO_ROOT = Path(__file__).resolve().parents[3]
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))

from src.fabric_contract_api import ( # noqa: E402
from fabric_chaincode_python.fabric_contract_api import (
Contract,
ContractChaincode,
TransactionContextInterface,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Fabric Chaincode Python - CCAAS Example
# Install dependencies with: pip install -r requirements.txt

grpcio>=1.83.1
protobuf>=3.20.0,<4.0.0
fabric-chaincode-python>=2.5.2
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,5 @@ examples/ccaas/fabric-contract-api/asset-transfer-sbe/
## References

- [fabric-shim version of this sample](../../fabric-shim/asset-transfer-sbe/)
- [fabric_contract_api documentation](../../../src/fabric_contract_api/README.md)
- [fabric_contract_api documentation](../../../../src/fabric_chaincode_python/fabric_contract_api/README.md)
- [Hyperledger Fabric SBE docs](https://hyperledger-fabric.readthedocs.io/en/latest/chaincode4no.html#state-based-endorsement)
18 changes: 1 addition & 17 deletions examples/ccaas/fabric-contract-api/asset-transfer-sbe/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,10 @@
from __future__ import annotations

import json
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import List

# Make sure the repository root is on ``sys.path`` so that the
# ``src.fabric_contract_api`` packages can be imported when the file is
# run directly.
_HERE = Path(__file__).resolve().parent
REPO_ROOT = None
for parent in [_HERE, *_HERE.parents]:
if (parent / "src" / "fabric_contract_api").is_dir():
REPO_ROOT = parent
break
if REPO_ROOT is None:
REPO_ROOT = Path(__file__).resolve().parents[3]
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))

from src.fabric_contract_api import ( # noqa: E402
from fabric_chaincode_python.fabric_contract_api import (
Contract,
ContractChaincode,
TransactionContextInterface,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
# Token Chaincode Example Requirements
# Install with: pip install -r requirements.txt

# Parent package (fabric-chaincode-python)
# When running in the parent directory:
# -e ../..

# If running standalone, uncomment the direct dependencies:
# grpcio>=1.83.1
# protobuf>=3.20.0,<4.0.0
# grpclib>=0.4.3
fabric-chaincode-python>=2.5.2
14 changes: 7 additions & 7 deletions examples/ccaas/fabric-shim/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# fabric-shim Examples (CCAAS)

These examples use the low-level **`fabric_shim`** package directly. You
subclass [`Chaincode`](../../../src/fabric_shim/interfaces.py) and write
subclass [`Chaincode`](../../../src/fabric_chaincode_python/fabric_shim/interfaces.py) and write
`init` / `invoke` methods, dispatching on the function name by hand.

## When to choose fabric-shim
Expand Down Expand Up @@ -37,10 +37,10 @@ instructions. The common pattern is:
2. Build the CCAAS package using the example's `connection.json` /
`metadata.json`.
3. `peer lifecycle chaincode install / approveformyorg / commit`.
4. Start the chaincode process:
```bash
export CHAINCODE_ID="<package_id>"
export CHAINCODE_SERVER_ADDRESS="127.0.0.1:9999"
python examples/ccaas/fabric-shim/<example-name>/main.py
```
4. Start the chaincode process (use the repository virtualenv):
```bash
export CHAINCODE_ID="<package_id>"
export CHAINCODE_SERVER_ADDRESS="127.0.0.1:9999"
./.venv/bin/python examples/ccaas/fabric-shim/<example-name>/main.py
```
5. `peer chaincode invoke` / `query` against the running chaincode.
24 changes: 4 additions & 20 deletions examples/ccaas/fabric-shim/asset-transfer-basic/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,10 @@
"""

import json
import sys
from pathlib import Path

# Make sure the repository root is on ``sys.path`` so that the
# ``src.fabric_shim`` packages can be imported when the file is run directly.
# Walk up the parent chain looking for the directory that contains ``src/``.
_HERE = Path(__file__).resolve().parent
REPO_ROOT = None
for parent in [_HERE, *_HERE.parents]:
if (parent / "src" / "fabric_shim").is_dir():
REPO_ROOT = parent
break
if REPO_ROOT is None:
REPO_ROOT = Path(__file__).resolve().parents[3]
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))

from src.fabric_shim.interfaces import Chaincode, ChaincodeStubInterface
from src.fabric_shim.server import start
from src.fabric_shim.response import ResponseCode

from fabric_chaincode_python.fabric_shim.interfaces import Chaincode, ChaincodeStubInterface
from fabric_chaincode_python.fabric_shim.server import start
from fabric_chaincode_python.fabric_shim.response import ResponseCode
from fabric_protos.peer import proposal_response_pb2 as pb


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Fabric Chaincode Python - CCAAS Example
# Install dependencies with: pip install -r requirements.txt

grpcio>=1.83.1
protobuf>=3.20.0,<4.0.0
fabric-chaincode-python>=2.5.2
Loading
Loading