Skip to content

Commit c96abac

Browse files
authored
Merge branch 'develop' into kano-definitions
2 parents 0fdc067 + 8a81915 commit c96abac

File tree

10 files changed

+1086
-788
lines changed

10 files changed

+1086
-788
lines changed

.github/workflows/github-pages.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ jobs:
2626
--metadata title="README" \
2727
-o dist/index.html
2828
29-
cp ./logo.png ./dist/logo.png
29+
cp ./logo/OpenCloudMesh-text-vertical-300x116.png ./dist/logo.png
30+
cp -R ./logo ./dist/logo
3031
cp ./docs.html ./dist/docs.html
31-
3232
- name: Upload Pages artifact
3333
uses: actions/upload-pages-artifact@v3
3434
with:

HISTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,5 @@ The Open Cloud Mesh initiative started in 2015 within the [GÉANT Association](h
4848
### [Sovereign Tech](https://www.sovereign.tech) funded efforts
4949
* In October 2025 a [grant was awarded](https://www.sovereign.tech/programs/fund) with a set of milestones to implement several missing pieces and introduce automated testing in each vendor's CI pipeline, as well as to support the IETF standardization efforts. This engagement was first made public at the [Open Source at CERN in 2025/2026 event](https://indico.cern.ch/event/1546072), featuring a number of funding agencies including Sovereign Tech, with a [lightning talk](https://indico.cern.ch/event/1546072/contributions/6754920) about CERNBox and OCM.
5050
* Presentations and demonstrations about the OCM-based EOSC Federation of Cloud Storage Systems at the [EOSC Symposium 2025](https://indico.cern.ch/event/1543880/timetable).
51+
* First [IETF WG interim meeting](https://datatracker.ietf.org/doc/agenda-interim-2025-ocm-01-ocm-01) held in November 2025 ([recording](https://www.youtube.com/watch?v=I9c6sFM2NZ8)): the draft is officially adopted by the WG.
52+
* [16th SIG-CISS Meet-up on Federated Storage and Storage Infrastructure](https://events.geant.org/event/1939) ([recording](https://drive.google.com/drive/folders/1EvvKgxTXO5UtQ0UBRuQaECvAhHgRMLxr)) featured a number of presentations about storage federations and OCM, with an OCM 10th anniversary presentation.

IETF-RFC.md

Lines changed: 224 additions & 171 deletions
Large diffs are not rendered by default.

IETF-RFC.xml

Lines changed: 464 additions & 464 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
# Open Cloud Mesh Protocol Specification
77

8-
This repository contains the text of the [Open Cloud Mesh IETF Draft](https://datatracker.ietf.org/doc/draft-lopresti-open-cloud-mesh/), as well as the equivalent [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (fka Swagger) specification for its API rendered as HTML (by [ReDoc](https://github.com/Redocly/redoc)).
8+
This repository contains the text of the [Open Cloud Mesh IETF Draft](https://datatracker.ietf.org/doc/draft-ietf-ocm-open-cloud-mesh/), as well as the equivalent [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (fka Swagger) specification for its API rendered as HTML (by [ReDoc](https://github.com/Redocly/redoc)).
99

1010
The documents are available as follows:
1111
* **Latest official version, 1.2.2**: [RFC-formatted Draft](https://github.com/cs3org/OCM-API/blob/v1.2.2/IETF-RFC.md) | [API spec](https://cs3org.github.io/OCM-API/docs.html?branch=v1.2.2&repo=OCM-API&user=cs3org)

diagrams/code-flow.puml

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,35 @@
11
@startuml
22

3-
participant "Alice" as Alice_user #fdf2d0
3+
actor "Alice" as Alice_user #fdf2d0
44
participant "EFSS" as Alice_EFSS #fdf2d0
55
participant "Disco" as Alice_Disco #fdf2d0
66
participant "Disco" as Bob_Disco #eececd
7-
participant "EFSS" as Bob_OCM #eececd
8-
participant "Bob" as Bob_user #eececd
9-
Bob_user -> Bob_OCM: Add contact 'Alice'
10-
Bob_user -> Alice_user: OCM invite [ token, FQDN ]
11-
Alice_user -> Alice_EFSS: Add contact 'Bob'
12-
Alice_EFSS -> Bob_OCM: POST /invite_accept [ token ]
13-
Bob_OCM -> Alice_EFSS: 201 created
7+
participant "EFSS" as Bob_EFSS #eececd
8+
actor "Bob" as Bob_user #eececd
9+
==Invite==
10+
Bob_user -> Bob_EFSS: Create token for 'Alice'
11+
Bob_EFSS -> Bob_user: token
12+
Bob_user -> Alice_user: OCM invite [ inviteString (token@Bob_FQDN) ]
13+
Alice_user -> Alice_EFSS: Add contact [ inviteString ]
14+
Alice_EFSS -> Bob_EFSS: **POST /ocm/invite-accepted** [ token ]
15+
Bob_EFSS -> Bob_user: 'Alice' is a trusted contact
16+
Bob_EFSS --> Alice_EFSS: 201 created
17+
Alice_EFSS -> Alice_user: 'Bob' is a trusted contact
18+
==Share==
1419
Alice_user -> Alice_EFSS: Share doc with 'Bob'
1520
Alice_EFSS -> Bob_Disco: GET /.well-known/ocm
1621
Bob_Disco -> Alice_EFSS: endpoints, capabilities, pubkey
17-
Alice_EFSS -> Bob_OCM: (signed) POST /ocm/share
18-
Bob_OCM -> Alice_Disco: GET /.well-known/ocm
19-
Alice_Disco -> Bob_OCM: pubkey
20-
Bob_OCM -> Alice_EFSS: 201 created
21-
Bob_OCM -> Alice_EFSS: (signed) /ocm/token
22-
Alice_EFSS -> Bob_OCM: short-lived bearer token
23-
Bob_OCM --> Alice_EFSS: (bearer) PROPFIND
24-
Alice_EFSS -> Bob_OCM: OK
22+
Alice_EFSS -> Bob_EFSS: (signed) **POST /ocm/share** [ refreshToken ]
23+
Bob_EFSS -> Alice_Disco: GET /.well-known/ocm
24+
Alice_Disco -> Bob_EFSS: pubkey
25+
Bob_EFSS --> Alice_EFSS: 201 created
26+
Bob_EFSS -> Bob_user: doc was shared by 'Alice'
27+
==Access==
28+
Bob_user -> Bob_EFSS: Access Alice's doc
29+
Bob_EFSS -> Alice_EFSS: (signed) **POST /ocm/token** [ refreshToken ]
30+
Alice_EFSS -> Bob_EFSS: short-lived bearer token
31+
Bob_EFSS -> Alice_EFSS: (bearer) PROPFIND
32+
Alice_EFSS --> Bob_EFSS: OK
33+
Bob_EFSS -> Bob_user: Display doc
2534

26-
@enduml
35+
@enduml

diagrams/invitation-flow.md

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,89 @@
11
```mermaid
22
sequenceDiagram
3-
participant Inviter
4-
participant InviteSenderServer as Invite Sender Server
5-
participant InviteReceiverServer as Invite Receiver Server
6-
participant Invitee
73
8-
Inviter->>InviteSenderServer: Calls Invite API
9-
InviteSenderServer->>InviteSenderServer: Creates an invite record in the database
10-
Note right of InviteSenderServer: Dispatch notification (Email) to invitee\n- Token\n- invite sender server FQDN
4+
%% Instance A components
5+
box "Instance A" #0f2749
6+
participant InviteManagerA as InviteManager A
7+
participant GatewayA as Gateway A
8+
participant HTTPA as HTTP API A (ocm, sm)
9+
end
1110
12-
InviteSenderServer->>Invitee: Send Email with Token and Server FQDN
13-
Invitee->>InviteReceiverServer: Submit invite acceptance form\n(Token, invite sender server FQDN)
14-
15-
InviteReceiverServer->>InviteSenderServer: Discover the OCM API of the inviter server
16-
InviteReceiverServer->>InviteReceiverServer: Adds FQDN of invite sender server as trusted server
11+
%% OCM Invitation Flow
12+
%% Actors
13+
actor UserA as Alice
14+
actor UserB as Bob
15+
16+
%% Instance B components
17+
box "Instance B" #0f2749
18+
participant HTTPB as HTTP API B (ocm, sm)
19+
participant GatewayB as Gateway B
20+
participant InviteManagerB as InviteManager B
21+
end
22+
23+
%% Invitation creation
24+
UserA ->> HTTPA: POST /generate-invite (ocm, sm)
25+
HTTPA ->> GatewayA: /generate-invite
26+
GatewayA ->> InviteManagerA: GenerateInviteToken
27+
Note right of InviteManagerA: store token in database
28+
InviteManagerA -->> GatewayA: return token
29+
GatewayA -->> HTTPA: return token
1730
18-
InviteReceiverServer->>InviteSenderServer: Accept invite API Call\n(InviteAcceptanceRequestDto)
19-
Note left of InviteReceiverServer: InviteAcceptanceRequestDto\n+ recipientProvider: string\n+ token: string\n+ userID: string\n+ email: string\n+ name: string
31+
alt
32+
HTTPA ->> UserB: Send Email with Alice's Server FQDN and Token
33+
else
34+
HTTPA ->> UserA: Raw or Base64 encoded "token@FQDN"
35+
UserA ->> UserB: Aice passes token to Bob
36+
end
2037
21-
InviteSenderServer->>InviteSenderServer: Add invite receiver FQDN as trusted server
22-
InviteSenderServer->>InviteSenderServer: Mark the invitation record as accepted
23-
InviteSenderServer->>InviteSenderServer: Add invite receiver in the contacts table
24-
InviteSenderServer->>InviteReceiverServer: Return InviteAcceptanceResponseDto
38+
alt
39+
UserB ->> UserB: Accept token manually in the EFSS UI
40+
UserB ->> HTTPB: POST /accept-invite (ocm, sm)
41+
else Use WAYF
42+
UserB ->> HTTPA: TODO
43+
end
44+
45+
%% Invitation acceptance on B
46+
UserB ->> HTTPB: POST /accept-invite (ocm, sm)
47+
HTTPB ->> GatewayB: ForwardInvite
48+
GatewayB ->> InviteManagerB: ForwardInvite
49+
InviteManagerB ->> HTTPA: Discover the OCM API of the inviter server
50+
HTTPA ->>InviteManagerB: OCM discovery data
51+
InviteManagerB ->> InviteManagerB: Adds FQDN of invite sender server as trusted server
52+
InviteManagerB ->> HTTPA: POST /invite-accepted (ocm)
53+
rect rgb(191, 223, 255)
54+
Note right of UserB: InviteAcceptanceRequestDto
55+
rect
56+
Note right of UserB: recipientProvider: string
57+
Note right of UserB: token: string
58+
Note right of UserB: userID: string
59+
Note right of UserB: email: string
60+
Note right of UserB: name: string
61+
end
62+
end
63+
64+
%% Process acceptance on A
65+
HTTPA ->> GatewayA: AcceptInvite
66+
GatewayA ->> InviteManagerA: AcceptInvite
67+
Note right of InviteManagerA: get token from database
68+
InviteManagerA ->> InviteManagerA: Add Bob's server FQDN as trusted server
69+
InviteManagerA ->> InviteManagerA: Mark the invitation record as accepted
70+
InviteManagerA ->> InviteManagerA: Add Bob in the contacts table
71+
InviteManagerA -->> GatewayA: return Alice user
72+
GatewayA -->> HTTPA: return Alice user
2573
26-
Note right of InviteReceiverServer: InviteAcceptanceResponseDto\n+ UserId: string\n+ Email: string\n+ Name: string
27-
InviteReceiverServer->>Invitee: Adds Invite sender as contact
74+
%% Propagation to B
75+
HTTPA ->> InviteManagerB: return Alice user
76+
rect rgb(191, 223, 255)
77+
Note right of UserA: InviteAcceptanceResponseDto
78+
rect
79+
Note right of UserA: userID: string
80+
Note right of UserA: email: string
81+
Note right of UserA: name: string
82+
end
83+
end
84+
InviteManagerB ->> InviteManagerB: Add Alice in the contacts table
85+
InviteManagerB -->> GatewayB: return
86+
GatewayB -->> HTTPB: return
87+
HTTPB -->> UserB: return
88+
2889
```

docs.html

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,64 @@
33
<head>
44
<title>Open Cloud Mesh API Reference Documentation</title>
55
<!-- needed for adaptive design -->
6-
<meta charset="utf-8"/>
6+
<meta charset="utf-8" />
77
<meta name="viewport" content="width=device-width, initial-scale=1">
88
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
99

1010
<!--
11-
ReDoc doesn't change outer page styles
12-
-->
11+
ReDoc doesn't change outer page styles
12+
-->
1313
<style>
1414
body {
1515
margin: 0;
1616
padding: 0;
1717
}
1818
</style>
1919
</head>
20+
2021
<body>
2122
<redoc></redoc>
2223
<script>
2324
const params = new URLSearchParams(window.location.search);
24-
const user = params.get('user');
25-
const repo = params.get('repo');
26-
const branch = params.get('branch');
27-
let changed = false;
28-
if (user === null) {
29-
params.set('user', 'cs3org');
30-
changed = true;
31-
}
32-
if (repo === null) {
33-
params.set('repo', 'OCM-API');
34-
changed = true;
35-
}
36-
if (branch === null) {
37-
params.set('branch', 'develop');
38-
changed = true;
25+
26+
const defaults = {
27+
user: 'cs3org',
28+
repo: 'OCM-API',
29+
branch: 'develop'
30+
};
31+
32+
let mutated = false;
33+
for (const key in defaults) {
34+
if (!params.has(key)) {
35+
params.set(key, defaults[key]);
36+
mutated = true;
37+
}
3938
}
40-
if (changed) {
39+
40+
if (mutated) {
4141
params.sort();
42-
window.location = `?${params.toString()}`;
42+
window.location.replace('?' + params.toString());
4343
}
44-
document.querySelector('redoc').setAttribute('spec-url', `https://raw.githubusercontent.com/${user}/${repo}/${branch}/spec.yaml`);
44+
45+
const user = params.get('user');
46+
const repo = params.get('repo');
47+
const branch = params.get('branch');
48+
49+
const specUrl =
50+
`https://raw.githubusercontent.com/${user}/${repo}/${branch}/spec.yaml`;
51+
52+
const redocScriptUrl =
53+
`https://cdn.redoc.ly/redoc/v3.0.0-rc.0/redoc.standalone.js`;
54+
55+
const redocEl = document.querySelector('redoc');
56+
redocEl.setAttribute('spec-url', specUrl);
57+
58+
const script = document.createElement('script');
59+
script.src = redocScriptUrl;
60+
script.type = 'module';
61+
script.async = true;
62+
script.defer = true;
63+
document.body.appendChild(script);
4564
</script>
46-
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
4765
</body>
4866
</html>

schemas/ocm-discovery.json

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
{
2+
"title": "OCM API Discovery",
3+
"$schema": "https://json-schema.org/draft/2020-12/schema",
4+
"type": "object",
5+
"properties": {
6+
"enabled": {
7+
"type": "boolean"
8+
},
9+
"apiVersion": {
10+
"type": "string"
11+
},
12+
"endPoint": {
13+
"type": "string",
14+
"format": "uri"
15+
},
16+
"provider": {
17+
"type": "string"
18+
},
19+
"resourceTypes": {
20+
"type": "array",
21+
"items": { "$ref": "#/$defs/resourceType" }
22+
},
23+
"capabilities": {
24+
"type": "array",
25+
"description": "Capabilities values of 'exchange-token', 'webdav-uri', 'protocol-object', 'invites', 'invite-wayf' defined in draft",
26+
"items": {
27+
"type": "string"
28+
}
29+
},
30+
"criteria": {
31+
"type": "array",
32+
"description": "Criteria values of 'http-request-signatures', 'token-exchange', 'denlyist' and 'allowlist' are defined in draft",
33+
"items": {
34+
"type": "string"
35+
}
36+
},
37+
"publicKey": {
38+
"$ref": "#/$defs/publicKey"
39+
},
40+
"inviteAcceptDialog": {
41+
"type": "string",
42+
"format": "uri"
43+
},
44+
"tokenEndPoint": {
45+
"type": "string",
46+
"format": "uri"
47+
}
48+
},
49+
"required": [
50+
"enabled",
51+
"apiVersion",
52+
"endPoint",
53+
"resourceTypes"
54+
],
55+
"$defs": {
56+
"resourceType": {
57+
"properties": {
58+
"name": {
59+
"type": "string"
60+
},
61+
"shareTypes": {
62+
"type": "array"
63+
},
64+
"protocols": { "$ref": "#/$defs/protocols" }
65+
},
66+
"required": ["name", "shareTypes", "protocols"]
67+
},
68+
"protocols": {
69+
"type": "object",
70+
"minProperties": 1,
71+
"description": "Additional protocols besides 'webdav', 'webapp' and 'datatx' may be defined.",
72+
"properties": {
73+
"webdav": {
74+
"type": "string",
75+
"pattern": "^/"
76+
},
77+
"webapp": {
78+
"type": "string",
79+
"pattern": "^/"
80+
},
81+
"datatx": {
82+
"type": "string",
83+
"pattern": "^/"
84+
}
85+
}
86+
},
87+
"publicKey": {
88+
"type": "object",
89+
"properties": {
90+
"keyId": {
91+
"type": "string"
92+
},
93+
"publicKeyPem": {
94+
"type": "string"
95+
}
96+
},
97+
"required": ["keyId", "publicKeyPem" ]
98+
99+
}
100+
}
101+
}

0 commit comments

Comments
 (0)