Skip to content

Commit 29f52bd

Browse files
committed
chore: addressed issues in PR comments
1 parent 9303f8e commit 29f52bd

11 files changed

Lines changed: 117 additions & 69 deletions

File tree

.github/workflows/test.yml

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Test Python open payments sdk f
1+
name: Test Python open payments sdk
22

33
on:
44
push:
@@ -10,11 +10,12 @@ on:
1010

1111
jobs:
1212
test:
13-
runs-on: ubuntu-latest
13+
runs-on: ${{ matrix.os }}
1414

1515
strategy:
1616
matrix:
17-
python-version: [3.11, 3.12, 3.13]
17+
os: [ubuntu-latest, windows-latest]
18+
python-version: [3.9,3.10,3.11, 3.12, 3.13]
1819

1920
steps:
2021
- name: Checkout code
@@ -25,13 +26,10 @@ jobs:
2526
with:
2627
python-version: ${{ matrix.python-version }}
2728

28-
- name: Install Poetry
29+
- name: Setup Poetry
2930
run: |
3031
curl -sSL https://install.python-poetry.org | python3 -
3132
echo "$HOME/.local/bin" >> $GITHUB_PATH
32-
33-
- name: Configure Poetry
34-
run: |
3533
poetry config virtualenvs.create false
3634
3735
- name: Install dependencies
@@ -42,3 +40,14 @@ jobs:
4240
- name: Run Unit Tests
4341
run: |
4442
poetry run pytest tests/unit/
43+
44+
audit:
45+
runs-on: ubuntu-latest
46+
steps:
47+
- uses: actions/checkout@v3
48+
- name: Install dependencies
49+
run: |
50+
python3 -m pip install . # assumes dependencies declared in pyproject.toml
51+
python3 -m pip install pip-audit
52+
- name: Run pip-audit
53+
run: pip-audit .

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,4 @@ poetry.toml
170170
pyrightconfig.json
171171

172172
# End of https://www.toptal.com/developers/gitignore/api/python
173-
privkey.pem
173+
privkey.pem

README.md

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,43 +21,47 @@ An Open Payments server runs two sub-systems, a resource server which exposes AP
2121

2222
## Local development
2323

24-
25-
2624
- Python >= 3.11
2725

2826
To install python visit [Python Download](https://www.python.org/downloads/)
27+
2928
- Poetry
3029
To install poetry visit [Poetry Documentation](https://python-poetry.org/docs/).
3130

3231
### Installation
3332

34-
1. Activate your virtual emvironment. No need to create one, Poetry creates one.
33+
1. Activate your virtual emvironment. No need to create one, Poetry creates one.
3534
Read [managing environments in Poetry](https://python-poetry.org/docs/managing-environments/).
3635

37-
3836
2. Install the dependencies in the poetry.lock
3937

4038
```
4139
> poetry install
4240
```
43-
## Usage
44-
To use this sdk, you will first need to install it in your project. Currently you will need to build from source but once it is hosted on pypi you will be able to install it with pip
41+
42+
## Usage
43+
44+
To use this SDK, you will first need to install it in your project. Currently, you will need to build from source but once it is hosted on PyPi you will be able to install it with `pip`.
4545

4646
```bash
4747
python3 -m pip install open-payments-python-sdk #currently not setup
4848
```
49+
4950
## Installing from source
5051

51-
Clone the repository
52+
Clone the repository
53+
5254
```bash
5355
git clone https://github.com/interledger/open-payments-python-sdk.git
5456
cd open-payments-python-sdk
5557
```
5658

5759
Build the package
60+
5861
```bash
5962
poetry build
6063
```
64+
6165
After running this command, the wheel package will be written to the `dist/` folder in the repo you just cloned
6266

6367
Install it in your project
@@ -67,6 +71,7 @@ pip install </path/to/>open-payments-python-sdk/dist/open_payments_sdk-0.1.0-py3
6771
```
6872

6973
# Initialising the Client
74+
7075
To create a client you can do so by importing the `OpenPaymentsClient` defined in the [`client`](./src/client/client.py) module and instantiating it.
7176

7277
```python
@@ -106,8 +111,10 @@ private_key = key_manager.load_ed25519_private_key_from_pem(
106111

107112
public_key = private_key.public_key() # derive public key from private key
108113
```
114+
109115
## Wallets
110-
You can use the created client to interact with the resource server. In this case we will use it to interact with a wallet address to get the wallet address details and jwks.json
116+
117+
You can use the created client to interact with the resource server. In this case we will use it to interact with a wallet address to get the wallet address details and jwks.json
111118

112119
```python
113120
#get wallet address
@@ -117,6 +124,7 @@ wallet_address_details = op_client.wallet.get_wallet_address("https://ilp.interl
117124
{'id': AnyUrl('https://ilp.interledger-test.dev/elijahokellosalary'), 'publicName': 'elijahokellosalary', 'assetCode': AssetCode(root='USD'), 'assetScale': AssetScale(root=2), 'authServer': AnyUrl('https://auth.interledger-test.dev/'), 'resourceServer': AnyUrl('https://ilp.interledger-test.dev/')}
118125

119126
```
127+
120128
Get Wallet jwks
121129

122130
```python
@@ -129,6 +137,7 @@ wallet_jwks = op_client.wallet.get_keys("https://ilp.interledger-test.dev/elijah
129137
```
130138

131139
## Grants
140+
132141
You can use the created client to request a grant from the authorization server. In this case we will use it to request a grant for an incoming payment resource. Check the [fixtures](./tests/conftest.py) file to see the request body.
133142

134143
```python

src/open_payments_sdk/api/auth.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
from open_payments_sdk.gnap_utils.security import SecurityBase
77
from open_payments_sdk.http import HttpClient
8-
from open_payments_sdk.models.auth import AccessToken
9-
from open_payments_sdk.models.auth import Grant as AuthGrant
8+
from open_payments_sdk.models.auth import AccessToken, Grant
109
from open_payments_sdk.models.auth import (GrantContinueResponse, GrantRequest,
1110
InteractRef)
11+
from open_payments_sdk.utils.utils import get_default_covered_components, get_default_headers
1212

1313

1414

@@ -25,14 +25,14 @@ def post_grant_request(
2525
self,
2626
grant_request: GrantRequest,
2727
auth_server_endpoint: str,
28-
) -> AuthGrant:
28+
) -> Grant:
2929
"""
3030
Grant Request
3131
"""
3232
data = grant_request.model_dump(exclude_unset=True, mode="json")
3333

3434
req_headers = {
35-
**self.get_default_headers()
35+
**get_default_headers()
3636
}
3737
request = self.http_client.build_request(
3838
method="POST",
@@ -41,9 +41,9 @@ def post_grant_request(
4141
headers=req_headers
4242
)
4343
request = self.set_content_digest(request=request)
44-
request = self.sign_request(request,("content-type","content-digest","content-length",*self.get_default_covered_components()))
44+
request = self.sign_request(request,("content-type","content-digest","content-length",*get_default_covered_components()))
4545
response = self.http_client.send(request=request)
46-
return response.json()
46+
return Grant.model_validate(response.json())
4747

4848
def post_grant_continuation_request(
4949
self,
@@ -56,7 +56,7 @@ def post_grant_continuation_request(
5656
"""
5757
data = interact_ref.model_dump(exclude_unset=True, mode="json")
5858
req_headers = {
59-
**self.get_default_headers(),
59+
**get_default_headers(),
6060
**self.get_auth_header(access_token=access_token)
6161
}
6262
request = self.http_client.build_request(
@@ -66,7 +66,7 @@ def post_grant_continuation_request(
6666
headers=req_headers
6767
)
6868
request = self.set_content_digest(request=request)
69-
request = self.sign_request(request,("content-type","content-digest","content-length","authorization",*self.get_default_covered_components()))
69+
request = self.sign_request(request,("content-type","content-digest","content-length","authorization",*get_default_covered_components()))
7070
response = self.http_client.send(request=request)
7171
return GrantContinueResponse.model_validate(response.json())
7272

@@ -89,7 +89,7 @@ def delete_grant(
8989
url=url,
9090
headers=req_headers
9191
)
92-
request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
92+
request = self.sign_request(request,("authorization",*get_default_covered_components()))
9393
self.http_client.send(request=request)
9494

9595
class AccessTokens(SecurityBase):
@@ -119,7 +119,7 @@ def post_rotate_access_token(
119119
url=url,
120120
headers=req_headers
121121
)
122-
request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
122+
request = self.sign_request(request,("authorization",*get_default_covered_components()))
123123
response = self.http_client.send(request=request)
124124
return AccessToken.model_validate(response.json())
125125

@@ -143,5 +143,5 @@ def delete_access_token(
143143
url=url,
144144
headers=req_headers
145145
)
146-
request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
146+
request = self.sign_request(request,("authorization",*get_default_covered_components()))
147147
self.http_client.send(request=request)

src/open_payments_sdk/api/resource.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
PaginatedOutgoingPayments,
1414
PaymentListQuery, Quote,
1515
QuoteRequest)
16+
from open_payments_sdk.utils.utils import get_default_covered_components, get_default_headers
1617

1718

1819
class IncomingPayments(SecurityBase):
@@ -36,7 +37,7 @@ def post_create_payment(
3637
url = f"{base_url}/incoming-payments"
3738
data = payment.model_dump(exclude_unset=True, mode="json")
3839
req_headers = {
39-
**self.get_default_headers(),
40+
**get_default_headers(),
4041
**self.get_auth_header(access_token=access_token)
4142
}
4243
request = self.http_client.build_request(
@@ -46,7 +47,7 @@ def post_create_payment(
4647
headers=req_headers
4748
)
4849
request = self.set_content_digest(request=request)
49-
request = self.sign_request(request,("content-type","content-digest","content-length","authorization",*self.get_default_covered_components()))
50+
request = self.sign_request(request,("content-type","content-digest","content-length","authorization",*get_default_covered_components()))
5051
response = self.http_client.send(request=request)
5152
return IncomingPayment.model_validate(response.json())
5253

@@ -70,7 +71,7 @@ def get_incoming_payments(
7071
headers=req_headers,
7172
params=query_params
7273
)
73-
request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
74+
request = self.sign_request(request,("authorization",*get_default_covered_components()))
7475
response = self.http_client.send(request=request)
7576
return PaginatedIncomingPayments.model_validate(response.json())
7677

@@ -93,7 +94,7 @@ def get_incoming_payment(
9394
url=url,
9495
headers=req_headers
9596
)
96-
request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
97+
request = self.sign_request(request,("authorization",*get_default_covered_components()))
9798
response = self.http_client.send(request=request)
9899
return IncomingPaymentResponse.model_validate(response.json())
99100

@@ -116,7 +117,7 @@ def post_complete_incoming_payment(
116117
url=url,
117118
headers=req_headers
118119
)
119-
request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
120+
request = self.sign_request(request,("authorization",*get_default_covered_components()))
120121
response = self.http_client.send(request=request)
121122
return IncomingPayment.model_validate(response.json())
122123

@@ -141,7 +142,7 @@ def post_create_payment(
141142
url = f"{base_url}/outgoing-payments"
142143
data = payment.model_dump(exclude_unset=True, mode="json")
143144
req_headers = {
144-
**self.get_default_headers(),
145+
**get_default_headers(),
145146
**self.get_auth_header(access_token=access_token)
146147
}
147148
request = self.http_client.build_request(
@@ -151,7 +152,7 @@ def post_create_payment(
151152
headers=req_headers
152153
)
153154
request = self.set_content_digest(request=request)
154-
request = self.sign_request(request,("content-type","content-digest","content-length","authorization",*self.get_default_covered_components()))
155+
request = self.sign_request(request,("content-type","content-digest","content-length","authorization",*get_default_covered_components()))
155156
response = self.http_client.send(request=request)
156157
return OutgoingPayment.model_validate(response.json())
157158

@@ -176,7 +177,7 @@ def get_outgoing_payments(
176177
headers=req_headers,
177178
params=query_params
178179
)
179-
response = request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
180+
response = request = self.sign_request(request,("authorization",*get_default_covered_components()))
180181
self.http_client.send(request=request)
181182
return PaginatedOutgoingPayments.model_validate(response.json())
182183

@@ -198,7 +199,7 @@ def get_outgoing_payment(
198199
url=url,
199200
headers=req_headers
200201
)
201-
request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
202+
request = self.sign_request(request,("authorization",*get_default_covered_components()))
202203
response = self.http_client.send(request=request)
203204
return OutgoingPayment.model_validate(response.json())
204205

@@ -223,7 +224,7 @@ def post_create_quote(
223224
url = f"{base_url}/quotes"
224225
data = quote.model_dump(exclude_unset=True, mode="json")
225226
req_headers = {
226-
**self.get_default_headers(),
227+
**get_default_headers(),
227228
**self.get_auth_header(access_token=access_token)
228229
}
229230
request = self.http_client.build_request(
@@ -233,7 +234,7 @@ def post_create_quote(
233234
json=data
234235
)
235236
request = self.set_content_digest(request=request)
236-
request = self.sign_request(request,("content-type","content-digest","content-length","authorization",*self.get_default_covered_components()))
237+
request = self.sign_request(request,("content-type","content-digest","content-length","authorization",*get_default_covered_components()))
237238
response = self.http_client.send(request=request)
238239
return Quote.model_validate(response.json())
239240

@@ -256,6 +257,6 @@ def get_quote(
256257
url=url,
257258
headers=req_headers
258259
)
259-
request = self.sign_request(request,("authorization",*self.get_default_covered_components()))
260+
request = self.sign_request(request,("authorization",*get_default_covered_components()))
260261
response = self.http_client.send(request=request)
261262
return Quote.model_validate(response.json())

src/open_payments_sdk/gnap_utils/keys.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ def generate_key_pair(self) -> KeyPair:
4343
keypair = KeyPair(jwks=key_jwks, private_key_pem=private_key_pem)
4444
return KeyPair.model_validate(keypair)
4545

46-
def load_ed25519_private_key_from_pem(self,pem_str: Union[str, bytes]) -> Ed25519PrivateKey:
46+
def load_ed25519_private_key_from_pem(self,pem_bytes: Union[str, bytes]) -> Ed25519PrivateKey:
4747
"""
4848
Read private key from str or bytes string
4949
"""
50-
if isinstance(pem_str,str):
51-
pem_str = pem_str.encode("utf-8")
50+
if isinstance(pem_bytes,str):
51+
pem_bytes = pem_bytes.encode("utf-8")
5252

5353
private_key = serialization.load_pem_private_key(
54-
data=pem_str,
54+
data=pem_bytes,
5555
password=None
5656
)
5757

src/open_payments_sdk/gnap_utils/security.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,6 @@ def sign_request(self, message: Request, covered_component_ids: Sequence[str] )-
4444
label="sig1"
4545
)
4646
return message
47-
48-
def get_default_headers(self) -> dict:
49-
"""
50-
Get default headers
51-
"""
52-
return {
53-
"Content-Type": "application/json"
54-
}
55-
56-
def get_default_covered_components(self) -> tuple:
57-
"""
58-
Return default covered components
59-
"""
60-
return ("@method","@target-uri")
6147

6248
def set_content_digest(self, request: Request) -> Request:
6349
"""

0 commit comments

Comments
 (0)