Skip to content
This repository has been archived by the owner on Nov 22, 2024. It is now read-only.

Commit

Permalink
docs: Federation via ActivityPub: Bovine based example
Browse files Browse the repository at this point in the history
Signed-off-by: John Andersen <[email protected]>
  • Loading branch information
pdxjohnny committed Oct 16, 2023
1 parent 0cf0f22 commit 328a639
Showing 1 changed file with 188 additions and 0 deletions.
188 changes: 188 additions & 0 deletions docs/federation_activitypub.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Federation via ActivityPub

- Federation of SCITT events enables near real-time communication between supply
chains.
- Acceptance of claims to SCITT where payload data contains VEX, VSA, SBOM,
S2C2F alignment attestations, etc. has the side effect of enabling a
consistent pattern for notification of new vulnerability (OpenSSF Stream
8) and other Software Supply Chain Security data.
- References
- [7.](https://www.ietf.org/archive/id/draft-ietf-scitt-architecture-02.html#name-federation)
- https://www.w3.org/TR/activitypub/

## Dependencies

Install the SCITT API Emulator with the `federation-activitypub-bovine` extra.

```console
$ pip install -e .[federation-activitypub-bovine]
```

## Example of Federating Claims / Receipts Across SCITT Instances

> Please refer to the [Registration Policies](registration_policies.md) doc for
> more information about claim insert policies.
In this example Alice and Bob each have their own instance of SCITT. Alice's
insert policy differs from Bob's slightly. Alice and Bob's instances federate
with each other. This means when claims are inserted into one instance and are
given and entry ID and a receipt at notification is sent to the other instance.
The other instance decides if it wants to create a corresponding entry ID and
receipt local to it.

Federation can be helpful when some aspects of insert policy validation are
shared. By federating with entities an instance trusts for those aspects of
insert policy and instance and it's owner(s) may be able to reduce investment in
compute or other activities required for claim validation.

As a more specific example, entities may share a common set of insert policy
criteria defined in a collaborative manner (such as a working group).
Attestations of alignment to the [S2C2F](https://github.com/ossf/s2c2f/blob/main/specification/framework.md#appendix-relation-to-scitt)
are one such example. In addition to the requirements / evaluation criteria
defined by the OpenSSF's Supply Chain Integrity Working Group an entity may
desire to evaluate attestations of alignment with added requirements appropriate
to their usage/deployment context and it's threat model.

### Bring up the ActivityPub Server

First we install our dependencies

- https://codeberg.org/bovine/bovine
- Most of the tools need to be run from the directory with the SQLite database in them (`bovine.sqlite3`)
- https://bovine-herd.readthedocs.io/en/latest/deployment.html
- Bovine and associated libraries **require Python 3.11 or greater!!!**

```console
$ python --version
Python 3.11.5
```

```console
$ python -m venv .venv && \
. .venv/bin/activate && \
pip install -U pip setuptools wheel && \
pip install \
toml \
bovine{-store,-process,-pubsub,-herd,-tool} \
'https://codeberg.org/pdxjohnny/bovine/archive/activitystreams_collection_helper_enable_multiple_iterations.tar.gz#egg=bovine&subdirectory=bovine' \
'https://codeberg.org/pdxjohnny/mechanical_bull/archive/event_loop_on_connect_call_handlers.tar.gz#egg=mechanical-bull'
```

We create a basic ActivityPub server.

```python
from quart import Quart

from bovine_herd import BovineHerd
from bovine_pubsub import BovinePubSub

app = Quart(__name__)
BovinePubSub(app)
BovineHerd(app)
```

We'll run on port 5000 to avoid collisions with SCITT's default port. Keep this
running for the rest of the tutorial.

> TODO Integrate Quart app launch into `SCITTFederationActivityPubBovine`
> initialization.
```console
$ hypercorn app:app -b 0.0.0.0:5000
[2023-10-16 02:44:48 -0700] [36467] [INFO] Running on http://0.0.0.0:5000 (CTRL + C to quit)
```

### Bring up Bob's SCITT Instance

Populate Bob's federation config

**federation_bob/config.json**

```json
{
"domain": "http://localhost:5000",
"handle_name": "bob",
"workspace": "federation_bob"
}
```

Start the server

```console
$ rm -rf workspace_bob/
$ mkdir -p workspace_bob/storage/operations
$ scitt-emulator server --workspace workspace_bob/ --tree-alg CCF \
--federation scitt_emulator.federation_activitypub_bovine:SCITTFederationActivityPubBovine \
--federation-config-path federation_bob/config.json
```

Create claim from allowed issuer (`.org`) and from non-allowed (`.com`).

```console
$ scitt-emulator client create-claim --issuer did:web:example.com --content-type application/json --payload '{"sun": "yellow"}' --out claim.cose
Claim written to claim.cose
$ scitt-emulator client submit-claim --claim claim.cose --out claim.receipt.cbor
Claim registered with entry ID 1
Receipt written to claim.receipt.cbor
$ scitt-emulator client create-claim --issuer did:web:example.org --content-type application/json --payload '{"sun": "yellow"}' --out claim.cose
Claim written to claim.cose
$ scitt-emulator client submit-claim --claim claim.cose --out claim.receipt.cbor
Claim registered with entry ID 2
Receipt written to claim.receipt.cbor
```

### Bring up Alice's SCITT Instance

Populate Alice's federation config

**federation_alice/config.json**

```json
{
"domain": "http://localhost:5000",
"handle_name": "alice",
"workspace": "federation_alice"
}
```

Start the server

```console
$ rm -rf workspace_alice/
$ mkdir -p workspace_alice/storage/operations
$ scitt-emulator server --workspace workspace_alice/ --tree-alg CCF \
--federation scitt_emulator.federation_activitypub_bovine:SCITTFederationActivityPubBovine \
--federation-config-path federation_alice/config.json
```

Create claim from allowed issuer (`.org`) and from non-allowed (`.com`).

```console
$ scitt-emulator client create-claim --issuer did:web:example.com --content-type application/json --payload '{"sun": "yellow"}' --out claim.cose
Claim written to claim.cose
$ scitt-emulator client submit-claim --claim claim.cose --out claim.receipt.cbor
Traceback (most recent call last):
File "/home/alice/.local/bin/scitt-emulator", line 33, in <module>
sys.exit(load_entry_point('scitt-emulator', 'console_scripts', 'scitt-emulator')())
File "/home/alice/Documents/python/scitt-api-emulator/scitt_emulator/cli.py", line 22, in main
args.func(args)
File "/home/alice/Documents/python/scitt-api-emulator/scitt_emulator/client.py", line 196, in <lambda>
func=lambda args: submit_claim(
File "/home/alice/Documents/python/scitt-api-emulator/scitt_emulator/client.py", line 107, in submit_claim
raise_for_operation_status(operation)
File "/home/alice/Documents/python/scitt-api-emulator/scitt_emulator/client.py", line 43, in raise_for_operation_status
raise ClaimOperationError(operation)
scitt_emulator.client.ClaimOperationError: Operation error denied: 'did:web:example.com' is not one of ['did:web:example.org']

Failed validating 'enum' in schema['properties']['issuer']:
{'enum': ['did:web:example.org'], 'type': 'string'}

On instance['issuer']:
'did:web:example.com'

$ scitt-emulator client create-claim --issuer did:web:example.org --content-type application/json --payload '{"sun": "yellow"}' --out claim.cose
Claim written to claim.cose
$ scitt-emulator client submit-claim --claim claim.cose --out claim.receipt.cbor
Claim registered with entry ID 1
Receipt written to claim.receipt.cbor
```

0 comments on commit 328a639

Please sign in to comment.