Skip to content

Commit 0f1d278

Browse files
committed
Updates
- Add workflows - Fix linting errors
1 parent 3145ee0 commit 0f1d278

15 files changed

+153
-104
lines changed

.github/workflows/lint.yml

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3+
4+
name: Python package
5+
6+
on: [push, pull_request]
7+
8+
jobs:
9+
build:
10+
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
python-version: '3.x'
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v3
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
- name: Install dependencies
24+
run: |
25+
python -m pip install --upgrade pip
26+
python -m pip install flake8 pytest
27+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
28+
- name: Lint with flake8
29+
run: |
30+
# stop the build if there are Python syntax errors or undefined names
31+
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
32+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
33+
flake8 . --count --exit-zero --max-complexity=10 --indent-size=2 --max-line-length=127 --statistics
34+
- name: Test with pytest
35+
run: |
36+
pytest
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# This workflow will upload a Python Package to PyPI when a release is created
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3+
4+
# This workflow uses actions that are not certified by GitHub.
5+
# They are provided by a third-party and are governed by
6+
# separate terms of service, privacy policy, and support
7+
# documentation.
8+
9+
name: Upload Python Package
10+
11+
on:
12+
release:
13+
types: [published]
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
release-build:
20+
runs-on: ubuntu-latest
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: actions/setup-python@v5
26+
with:
27+
python-version: "3.x"
28+
29+
- name: Build release distributions
30+
run: |
31+
# NOTE: put your own distribution build steps here.
32+
python -m pip install build
33+
python -m build
34+
35+
- name: Upload distributions
36+
uses: actions/upload-artifact@v4
37+
with:
38+
name: release-dists
39+
path: dist/
40+
41+
pypi-publish:
42+
runs-on: ubuntu-latest
43+
needs:
44+
- release-build
45+
permissions:
46+
# IMPORTANT: this permission is mandatory for trusted publishing
47+
id-token: write
48+
49+
# Dedicated environments with protections for publishing are strongly recommended.
50+
# For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
51+
environment:
52+
name: pypi
53+
# OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
54+
# url: https://pypi.org/p/YOURPROJECT
55+
#
56+
# ALTERNATIVE: if your GitHub Release name is the PyPI project version string
57+
# ALTERNATIVE: exactly, uncomment the following line instead:
58+
# url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}
59+
60+
steps:
61+
- name: Retrieve release distributions
62+
uses: actions/download-artifact@v4
63+
with:
64+
name: release-dists
65+
path: dist/
66+
67+
- name: Publish release distributions to PyPI
68+
uses: pypa/gh-action-pypi-publish@release/v1
69+
with:
70+
packages-dir: dist/

.github/workflows/test.yml

Lines changed: 0 additions & 24 deletions
This file was deleted.

README.md

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ Other storage locations can be added at will simply by extending the
2121

2222
## Initial Setup And Installation
2323

24-
## Enable the APIs on Google Cloud
24+
### Enable the APIs on Google Cloud
2525

2626
In order to use the connectors to any of the Google Cloud storage methods
2727
(Secret Manager, Firestore and Google Cloud Storage) you will have to ensure
2828
that the relevant APIs have been enabled. Follow the instructions listed in the
2929
[developer documentation](https://cloud.google.com/apis/docs/getting-started)
3030
to enable the API you need.
3131

32-
## Ensure the app's service account has acces to the APIs
32+
### Ensure the app's service account has access to the APIs
3333

3434
## Implementation specific
3535

@@ -81,15 +81,12 @@ the usage cost of Secret Manager substantially as projects are charged based
8181
partially on number of _active_ and _disabled_ (ie not destroyed) secret
8282
versions.
8383

84-
You can also use [`KeyUploader`](#keyuploader).
84+
You can also use [`KeyUploader`](#keyuploader) to upload these data.
8585

8686
### Firestore
8787

88-
Firestore requires no additional configuration, although you will have to
89-
seed the Firestore database with the client secret data, much like with Secret
90-
Manager above. Unfortunately there is no CLI access through `gcloud` to
91-
Firestore so we can't write a simple shell script. In this case, please see
92-
below in the section on [`KeyUploader`](#keyuploader).
88+
Firestore requires no additional configuration, as it uses the service account's
89+
credentials to access the database.
9390

9491
### Google Cloud Storage
9592

@@ -177,17 +174,6 @@ supplied datastores. This will allow you to pre-load `Firestore` with the
177174
The file to be uploaded can be stored either locally or on
178175
`Google Cloud Storage`.
179176

180-
For example: to run the `KeyUploader` and install the client secrets file into
181-
Firestore, you would do the following:
182-
183-
```
184-
python auth.cli.key_upload.py \
185-
--key=client_secret \
186-
--firestore \
187-
--email=YOUR_EMAIL \
188-
--file=PATH/TO/client_secrets.json
189-
```
190-
191177
Your available command-line switches are:
192178

193179
| Switch | | Description |
@@ -205,3 +191,19 @@ Your available command-line switches are:
205191

206192
**NOTE** _One and only one_ of `--local`, `--firestore`, `--cloud_storage`
207193
and `--secret_manager` must be specified
194+
195+
For example: to run the `KeyUploader` and install the client secrets file into
196+
Firestore, you would do the following:
197+
198+
```
199+
python -m auth.cli.key_upload \
200+
--key=client_secret \
201+
--firestore \
202+
--email=YOUR_EMAIL \
203+
--file=PATH/TO/client_secrets.json
204+
```
205+
206+
This will create a collection called '`administration`', and add a document
207+
to it called '`client_secret`', with keys corresponding to the entire content
208+
of the json file.
209+

auth/credentials.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,17 @@
1313
# limitations under the License.
1414
from __future__ import annotations
1515

16+
import json
1617
from dataclasses import dataclass
1718
from datetime import datetime
18-
import json
1919
from typing import Any, Dict, Mapping, Type, TypeVar, Union
20-
from io import BytesIO
2120

2221
import pytz
2322
from dateutil.relativedelta import relativedelta
2423
from google.auth.transport import requests
2524
from google.oauth2 import credentials as oauth
2625

2726
from auth import decorators
28-
2927
from auth.abstract_datastore import AbstractDatastore
3028
from auth.credentials_helpers import encode_key
3129
from auth.exceptions import CredentialsError
@@ -126,10 +124,9 @@ def project_credentials(self) -> ProjectCredentials:
126124
client_secret.get('web') or \
127125
client_secret.get('installed')
128126

129-
creds = \
130-
ProjectCredentials(client_id=secrets['client_id'],
131-
client_secret=secrets['client_secret']) \
132-
if secrets else None
127+
creds = ProjectCredentials(client_id=secrets['client_id'],
128+
client_secret=secrets['client_secret']
129+
) if secrets else None
133130

134131
return creds
135132

@@ -177,8 +174,7 @@ def _to_utc(self, last_date: datetime) -> datetime:
177174
Returns:
178175
datetime: the date in UTC
179176
"""
180-
if (last_date.tzinfo is None or
181-
last_date.tzinfo.utcoffset(last_date) is None):
177+
if (last_date.tzinfo is None or last_date.tzinfo.utcoffset(last_date) is None):
182178
last_date = pytz.UTC.localize(last_date)
183179

184180
return last_date

auth/credentials_helpers_test.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import json
1615
import unittest
17-
from unittest import mock
1816

1917
from auth.credentials_helpers import encode_key
2018
from auth.exceptions import KeyEncodingError

auth/credentials_test.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
import unittest
1717
from unittest import mock
1818

19-
from auth.credentials_helpers import encode_key
20-
from auth.exceptions import KeyEncodingError
2119
from google.oauth2 import credentials as oauth
22-
from auth.credentials import Credentials
20+
2321
from auth import local_file
22+
from auth.credentials import Credentials
23+
from auth.credentials_helpers import encode_key
24+
from auth.exceptions import KeyEncodingError
2425

2526
MASTER_CONFIG = {
2627
"auth": {
@@ -40,13 +41,13 @@ class CredentialsTest(unittest.TestCase):
4041
def setUp(self):
4142
self.open = mock.mock_open(read_data=json.dumps(MASTER_CONFIG))
4243

43-
# def test_encode_valid(self) -> None:
44-
# self.assertEqual('YnV0dGVyY3VwQGFzeW91d2lzaC5jb20',
45-
# encode_key('[email protected]'))
44+
def test_encode_valid(self) -> None:
45+
self.assertEqual('YnV0dGVyY3VwQGFzeW91d2lzaC5jb20',
46+
encode_key('[email protected]'))
4647

47-
# def test_encode_none(self) -> None:
48-
# with self.assertRaisesRegex(KeyEncodingError, 'Cannot encode None'):
49-
# encode_key(None)
48+
def test_encode_none(self) -> None:
49+
with self.assertRaisesRegex(KeyEncodingError, 'Cannot encode None'):
50+
encode_key(None)
5051

5152
def test_store_credentials_with_creds(self) -> None:
5253
token = {"token": "token",

auth/datastore/cloud_storage.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
from __future__ import annotations
1515

1616
import json
17-
from typing import Any, Callable, Dict, List, Mapping, Optional
17+
from typing import Any, Dict
1818

1919
import gcsfs
2020
from auth import decorators
2121
from .file_datastore import FileDatastore
22+
from auth.abstract_datastore import AbstractDatastore
2223

2324

2425
class CloudStorage(FileDatastore):
@@ -29,7 +30,7 @@ def datastore(self) -> Dict[str, Any]:
2930
try:
3031
fs = gcsfs.GCSFileSystem(project=self.project)
3132
file_name = f'{self.bucket}/{self.datastore_file}'
32-
with open(file_name, 'r') as store:
33+
with fs.open(file_name, 'r') as store:
3334
if data := store.read():
3435
return json.loads(data)
3536
else:

auth/datastore/cloud_storage_test.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,11 @@
1414

1515
import json
1616
import unittest
17+
from copy import deepcopy
1718
from unittest import mock
1819

1920
from auth.datastore import cloud_storage
2021

21-
from copy import deepcopy
22-
from typing import Any, Dict
23-
2422
MASTER_CONFIG = {
2523
"auth": {
2624
"api_key": "api_key",

0 commit comments

Comments
 (0)