Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add note on traceability in the docs #26

Merged
merged 2 commits into from
Mar 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/discussions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,34 @@ See `PEP 503`__ for all the details.

.. __: https://www.python.org/dev/peps/pep-0503/#normalized-names

What would be good practice regarding token restrictions and traceability
-------------------------------------------------------------------------

PyPI offers quite a bit of interesting features regarding token traceability & audit:
- You can list your existing tokens, including a description of your choice
- You can revoke them
- You can see the restrictions applied at generation time by PyPI
- Other project admins can see if you generated tokens for projects you share with them

It's generally considered a good idea to use each token for one dedicated usage, so that
if you need to revoke a token, you don't break anything else.

Adding restrictions yourself on existing tokens have consequences on those elements:

- If two tokens are created by adding restrictions to a single "parent" token, revoking
the parent token will revoke all the children at the same time. Given it's still a
good idea to use a token for one usage only, when you generate a token with a
restriction, if you plan to store the child token, then you should consider throwing
away immediately the original token. Of course, this is not always applicable, some
use-cases may require to store both but you may need to track the diffusion of your
tokens yourself.
- In PyPI, restrictions you added yourself will not appear in the token list, so
it's a good idea to be overly explicit in the token description. Note that the
description field cannot be modified after generation.

This way, your PyPI account page will still be a good place to track all of your
existing tokens, and you will be able to follow each of them easily.

All this talking about Macaroons, I'm hungry now!
-------------------------------------------------

Expand Down
22 changes: 11 additions & 11 deletions tests/test_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class MyRestriction(token.Restriction):
version: int

@staticmethod
def get_schema():
def _get_schema():
return {
"type": "object",
"properties": {
Expand All @@ -30,10 +30,10 @@ def get_schema():
}

@classmethod
def extract_kwargs(cls, value):
def _extract_kwargs(cls, value):
return {"version": value["version"]}

assert MyRestriction.load_value(value={"version": 42}).version == 42
assert MyRestriction._load_value(value={"version": 42}).version == 42


@pytest.mark.parametrize(
Expand All @@ -49,7 +49,7 @@ def extract_kwargs(cls, value):
def test__Restriction__load_value__fail(value):
class MyRestriction(token.Restriction):
@staticmethod
def get_schema():
def _get_schema():
return {
"type": "object",
"properties": {
Expand All @@ -59,11 +59,11 @@ def get_schema():
}

with pytest.raises(exceptions.LoaderError):
MyRestriction.load_value(value=value)
MyRestriction._load_value(value=value)


def test__NoopRestriction__load_value__pass():
tok = token.NoopRestriction.load_value(value={"version": 1, "permissions": "user"})
tok = token.NoopRestriction._load_value(value={"version": 1, "permissions": "user"})
assert tok == token.NoopRestriction()


Expand All @@ -80,11 +80,11 @@ def test__NoopRestriction__load_value__pass():
)
def test__NoopRestriction__load_value__fail(value):
with pytest.raises(exceptions.LoaderError):
token.NoopRestriction.load_value(value=value)
token.NoopRestriction._load_value(value=value)


def test__NoopRestriction__extract_kwargs():
noop = token.NoopRestriction.extract_kwargs(value={"any": "content"})
noop = token.NoopRestriction._extract_kwargs(value={"any": "content"})
assert noop == {}


Expand Down Expand Up @@ -116,7 +116,7 @@ def test__NoopRestriction__dump():
],
)
def test__ProjectsRestriction__load_value__pass(value, restriction):
assert token.ProjectsRestriction.load_value(value=value) == restriction
assert token.ProjectsRestriction._load_value(value=value) == restriction


@pytest.mark.parametrize(
Expand All @@ -136,12 +136,12 @@ def test__ProjectsRestriction__load_value__pass(value, restriction):
)
def test__ProjectsRestriction__load_value__fail(value):
with pytest.raises(exceptions.LoaderError):
token.ProjectsRestriction.load_value(value=value)
token.ProjectsRestriction._load_value(value=value)


def test__ProjectsRestriction__extract_kwargs():
value = {"version": 1, "permissions": {"projects": ["a", "b"]}}
kwargs = token.ProjectsRestriction.extract_kwargs(value=value)
kwargs = token.ProjectsRestriction._extract_kwargs(value=value)
assert kwargs == {"projects": ["a", "b"]}


Expand Down