Skip to content

Commit

Permalink
Release
Browse files Browse the repository at this point in the history
  • Loading branch information
Derek Merck authored and Derek Merck committed Jan 26, 2019
1 parent 6ff2e5c commit f9a7491
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 25 deletions.
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Providence, RI

Sign and verify Python packages by version using a public gist.

See <https://gist.github.com/derekmerck/4b0bfbca0a415655d97f36489629e1cc> for my package signatures.

## Setup

```bash
Expand All @@ -24,11 +26,35 @@ $ export GIST_OAUTH_TOK=<github token>
$ gistsig store -g <gist_id> <pkgs>
$ gistsig verify -g <gist_id> <pkgs>
Process finished with exit code 0
$ echo "/n" >> <pkg>.py
$ echo "/n" >> <pkg>/main.py
$ gistsig verify -g <gist_id> <pkgs>
Process finished with exit code 1
```


## Algorithm

This simple signing algorithm is _only_ intended to verify that the scripts for an installed Python package have not been tampered with since that version was tested and released.

1. Find package path
2. `os.walk` the package path and filter for "*.py"
3. Concatenate the file contents in file path sorted order
4. Compute the sha1 digest of the result

This can be easily implemented from the command-line as well:

```bash
$ gistsig -g 4b0bfbca0a415655d97f36489629e1cc show diana
Local package has signature python-diana:2.0.13:9fec66ac3f4f87f8b933c853d8d5f49bdae0c1dc

$ python -c "import diana; print(diana.__version__)"
2.0.13

$ find $(python -c "import diana; print(diana.__path__[0])") -name *.py | sort -n | xargs cat| sha1sum
9fec66ac3f4f87f8b933c853d8d5f49bdae0c1dc
```


## License

MIT
2 changes: 2 additions & 0 deletions gistsig/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .gist import get_gist, update_gist
from .pkg_info import get_pkg_info
File renamed without changes.
35 changes: 21 additions & 14 deletions gs_cli.py → gistsig/gs_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@
Sign and verify Python packages using public gists.
"""

import logging, os
import logging
from pprint import pformat
from datetime import datetime
import click
from gist import get_gist, update_gist
from pkg_sig import get_pkg_key, get_pkg_hash
from gistsig import get_gist, update_gist, get_pkg_info


@click.group()
@click.option('--verbose', '-v', is_flag=True, default=False)
@click.option('--gist_id')
@click.option('--gist_oauth_tok')
@click.option('--gist_id', '-g', help="Public gist id with reference signatures.")
@click.option('--gist_oauth_tok', '-o', help="Github token (only if pushing new signatures)")
@click.pass_context
def cli(ctx, verbose, gist_id, gist_oauth_tok):
"""
Perform a simple public signature lookup to verify local Python package
files.
\b
Example:
$ gistsig -g 4b0bfbca0a415655d97f36489629e1cc show diana
Local package has signature python-diana:2.0.13:9fec66ac3f4f87f8b933c853d8d5f49bdae0c1dc
"""
ctx.obj['gist_id'] = gist_id
ctx.obj['gist_oauth_tok'] = gist_oauth_tok
if verbose:
Expand All @@ -31,11 +39,10 @@ def cli(ctx, verbose, gist_id, gist_oauth_tok):

@cli.command()
@click.argument('packages', nargs=-1)
@click.pass_context
def show(ctx, packages):
def show(packages):
"""Compute local package signature."""
for pkg_name in packages:
value = get_pkg_hash(pkg_name=pkg_name)
key = get_pkg_key(pkg_name=pkg_name)
key, value = get_pkg_info(pkg_name)
msg = click.style("Local package has signature {}:{}.".format(key, value), fg='yellow')
click.echo(msg)

Expand All @@ -44,6 +51,7 @@ def show(ctx, packages):
@click.argument("packages", nargs=-1)
@click.pass_context
def pull(ctx, packages):
"""Show public package signatures."""
gist_id = ctx.obj['gist_id']
for pkg_name in packages:
pkg_sigs = get_gist(gist_id=gist_id, name=pkg_name)
Expand All @@ -56,12 +64,11 @@ def pull(ctx, packages):
@click.argument("packages", nargs=-1)
@click.pass_context
def verify(ctx, packages):
"""Compare local to public package signatures."""
exit_code = 0
gist_id = ctx.obj['gist_id']
for pkg_name in packages:
key = get_pkg_key(pkg_name=pkg_name)
value = get_pkg_hash(pkg_name=pkg_name)

key, value = get_pkg_info(pkg_name)
pkg_sigs = get_gist(gist_id=gist_id, name=pkg_name)

ref = None
Expand All @@ -85,12 +92,12 @@ def verify(ctx, packages):
@click.argument("packages", nargs=-1)
@click.pass_context
def push(ctx, packages):
"""Update public package signatures"""
gist_id = ctx.obj['gist_id']
gist_oauth_tok = ctx.obj['gist_oauth_tok']
for pkg_name in packages:
pkg_sigs = get_gist(gist_id=gist_id, name="{}.json".format(pkg_name))
value = get_pkg_hash(pkg_name=pkg_name)
key = get_pkg_key(pkg_name=pkg_name)
key, value = get_pkg_info(pkg_name)
click.echo("Submitting signature {}:{}".format(key, value))
pkg_sigs[key] = { "hash": value,
"time": datetime.now().isoformat() }
Expand Down
26 changes: 19 additions & 7 deletions pkg_sig.py → gistsig/pkg_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,39 @@
from hashlib import sha1


def get_pkg_hash(pkg_name):
def get_pkg_hash(pkg):

pkg = __import__(pkg_name)
lines = ""
path = os.path.dirname(pkg.__loader__.path)
fps = []
for root, dir, files in os.walk(path):
for fn in files:
if os.path.splitext(fn)[-1] == ".py":
fp = Path(root, fn)
logging.debug(fp)
with open(fp) as f:
lines = lines + f.read()
fps.append(fp)

for fp in sorted(fps):
logging.debug(fp)
with open(fp) as f:
lines = lines + f.read()

s = sha1(lines.encode('utf-8')).hexdigest()
return s


def get_pkg_key(pkg_name):
def get_pkg_key(pkg):

pkg = __import__(pkg_name)
sig = "{n}:{v}".format(n=pkg.__name__,
v=pkg.__version__)
return sig


def get_pkg_info(pkg_name):

pkg = __import__(pkg_name)

value = get_pkg_hash(pkg=pkg)
key = get_pkg_key(pkg=pkg)

return key, value

5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

metadata = {
'name': "gistsig",
'version': "1.1.1",
'version': "1.1.2",
'author': "Derek Merck",
'author_email': "derek_merck@brown.edu"
}
Expand All @@ -20,7 +20,6 @@
long_description_content_type="text/markdown",
url="https://github.com/derekmerck/gistsig",
packages=setuptools.find_packages(),
include_package_data=True,
classifiers=(
'Development Status :: 3 - Alpha',
"Programming Language :: Python :: 3",
Expand All @@ -30,6 +29,6 @@
license='MIT',
entry_points='''
[console_scripts]
gistsig=gs_cli:_cli
gistsig=gistsig.gs_cli:_cli
''',
)

0 comments on commit f9a7491

Please sign in to comment.