This repository has been archived by the owner on Nov 22, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: Federation via ActivityPub: Bovine based example
Signed-off-by: John Andersen <[email protected]>
- Loading branch information
Showing
1 changed file
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |