Skip to content

Commit 4bd298c

Browse files
committed
[ADD] Create CFSSL Library
1 parent 256c2af commit 4bd298c

File tree

10 files changed

+612
-14
lines changed

10 files changed

+612
-14
lines changed

.codeclimate.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
languages:
2+
JavaScript: false
3+
Python: true

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ addons:
22
apt:
33
packages:
44
- expect-dev # provides unbuffer utility
5-
- unixodbc-dev
65

76
language: python
87

@@ -15,7 +14,8 @@ virtualenv:
1514
install:
1615
- pip install coveralls
1716
- pip install codecov --user
18-
- pip install -r test_requirements.txt
17+
- pip install codeclimate-test-reporter
18+
- pip install -r requirements.txt
1919
- pip install .
2020

2121
# command to run tests
@@ -25,3 +25,4 @@ script:
2525
after_success:
2626
- coveralls
2727
- codecov
28+
- codeclimate-test-reporter

README.rst

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,30 @@
1-
# cfssl-py
2-
Python Library for CloudFlare CFSSL
1+
| |Build Status| | |Coveralls Status| | |Codecov Status| | |Code Climate|
2+
3+
Python CFSSL Library
4+
====================
5+
6+
This library allows you to interact with a remote CFSSL using Python.
7+
8+
Installation
9+
------------
10+
11+
Setup
12+
-----
13+
14+
Usage
15+
-----
16+
17+
Known Issues / Road Map
18+
-----------------------
19+
20+
- Installation, setup, usage - in ReadMe
21+
- Add a Certificate Request data structure
22+
23+
.. |Build Status| image:: https://api.travis-ci.org/laslabs/Python-CFSSL.svg?branch=master
24+
:target: https://travis-ci.org/laslabs/Python-CFSSL
25+
.. |Coveralls Status| image:: https://coveralls.io/repos/laslabs/Python-CFSSL/badge.svg?branch=master
26+
:target: https://coveralls.io/r/laslabs/Python-CFSSL?branch=master
27+
.. |Codecov Status| image:: https://codecov.io/gh/laslabs/Python-CFSSL/branch/master/graph/badge.svg
28+
:target: https://codecov.io/gh/laslabs/Python-CFSSL
29+
.. |Code Climate| image:: https://codeclimate.com/github/laslabs/Python-CFSSL/badges/gpa.svg
30+
:target: https://codeclimate.com/github/laslabs/Python-CFSSL

cfssl/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License MIT (https://opensource.org/licenses/MIT).
4+
5+
from .cfssl import CFSSL

cfssl/cfssl.py

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

cfssl/exceptions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License MIT (https://opensource.org/licenses/MIT).
4+
5+
import requests
6+
7+
8+
class CFSSLException(EnvironmentError):
9+
""" This exception is raised from errors in the CFSSL Library. """
10+
11+
12+
class CFSSLRemoteException(CFSSLException):
13+
""" This exception is raised to indicate issues returned from API. """

cfssl/tests/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License MIT (https://opensource.org/licenses/MIT).

cfssl/tests/test_cfssl.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2016 LasLabs Inc.
3+
# License MIT (https://opensource.org/licenses/MIT).
4+
5+
import mock
6+
import unittest
7+
8+
from ..cfssl import CFSSL, CFSSLRemoteException, requests
9+
10+
11+
class TestCFSSL(unittest.TestCase):
12+
13+
def setUp(self):
14+
super(TestCFSSL, self).setUp()
15+
self.cfssl = CFSSL('test', 1)
16+
17+
def test_uri_base_https(self):
18+
""" It should have an HTTP URI by default """
19+
self.assertIn('https://', self.cfssl.uri_base)
20+
21+
def test_uri_base_http(self):
22+
""" It should have an HTTP URI if someone decides to be crazy """
23+
cfssl = CFSSL('test', 1, False)
24+
self.assertIn('http://', cfssl.uri_base)
25+
26+
@mock.patch.object(CFSSL, 'call')
27+
def test_auth_sign(self, call):
28+
""" It should call with proper args """
29+
expect = {
30+
'token': 'token',
31+
'request': 'request',
32+
}
33+
self.cfssl.auth_sign(**expect)
34+
call.assert_called_once_with(
35+
'authsign', 'POST', data=expect
36+
)
37+
38+
@mock.patch.object(CFSSL, 'call')
39+
def test_bundle(self, call):
40+
""" It should call with proper args """
41+
expect = {
42+
'certificate': 'certificate',
43+
'flavor': 'flavor',
44+
}
45+
self.cfssl.bundle(**expect)
46+
call.assert_called_once_with(
47+
'bundle', 'POST', data=expect
48+
)
49+
50+
@mock.patch.object(CFSSL, 'call')
51+
def test_info(self, call):
52+
""" It should call with proper args """
53+
expect = {
54+
'label': 'label',
55+
}
56+
self.cfssl.info(**expect)
57+
call.assert_called_once_with(
58+
'info', 'POST', data=expect
59+
)
60+
61+
@mock.patch.object(CFSSL, 'call')
62+
def test_init_ca(self, call):
63+
""" It should call with proper args """
64+
expect = {
65+
'hosts': 'hosts',
66+
'names': 'names',
67+
'common_name': 'cn'
68+
}
69+
self.cfssl.init_ca(**expect)
70+
expect['CN'] = 'cn'
71+
del expect['common_name']
72+
call.assert_called_once_with(
73+
'init_ca', 'POST', data=expect
74+
)
75+
76+
@mock.patch.object(CFSSL, 'call')
77+
def test_new_key(self, call):
78+
""" It should call with proper args """
79+
expect = {
80+
'hosts': 'hosts',
81+
'names': 'names',
82+
'common_name': 'cn'
83+
}
84+
self.cfssl.new_key(**expect)
85+
expect['CN'] = 'cn'
86+
del expect['common_name']
87+
call.assert_called_once_with(
88+
'newkey', 'POST', data=expect
89+
)
90+
91+
@mock.patch.object(CFSSL, 'call')
92+
def test_new_cert(self, call):
93+
""" It should call with proper args """
94+
expect = {
95+
'request': 'request',
96+
'label': 'label',
97+
}
98+
self.cfssl.new_cert(**expect)
99+
call.assert_called_once_with(
100+
'newcert', 'POST', data=expect
101+
)
102+
103+
@mock.patch.object(CFSSL, 'call')
104+
def test_revoke(self, call):
105+
""" It should call with proper args """
106+
expect = {
107+
'serial': 'Ben-S',
108+
'authority_key_id': 'REVOKE!',
109+
'reason': 'The derphead lost it',
110+
}
111+
self.cfssl.revoke(**expect)
112+
call.assert_called_once_with(
113+
'revoke', 'POST', data=expect
114+
)
115+
116+
@mock.patch.object(CFSSL, 'call')
117+
def test_scan(self, call):
118+
""" It should call with proper args """
119+
expect = {
120+
'host': 'host',
121+
}
122+
self.cfssl.scan(**expect)
123+
call.assert_called_once_with(
124+
'scan', params=expect
125+
)
126+
127+
@mock.patch.object(CFSSL, 'call')
128+
def test_scan_info(self, call):
129+
""" It should call with proper args """
130+
self.cfssl.scan_info()
131+
call.assert_called_once_with('scaninfo')
132+
133+
@mock.patch.object(CFSSL, 'call')
134+
def test_sign(self, call):
135+
""" It should call with proper args """
136+
expect = {
137+
'certificate_request': 'certificate_request',
138+
}
139+
self.cfssl.sign(**expect)
140+
call.assert_called_once_with(
141+
'sign', 'POST', data=expect
142+
)
143+
144+
@mock.patch.object(requests, 'request')
145+
def test_call_request(self, requests):
146+
""" It should call requests with proper args """
147+
self.cfssl.call('endpoint', 'method', 'params', 'data')
148+
requests.assert_called_once_with(
149+
method='method',
150+
url='https://test:1/api/v1/cfssl/endpoint',
151+
params='params',
152+
data='data',
153+
)
154+
155+
@mock.patch.object(requests, 'request')
156+
def test_call_error(self, requests):
157+
""" It should raise on non-success response """
158+
requests().json.return_value = {'success': False}
159+
with self.assertRaises(CFSSLRemoteException):
160+
self.cfssl.call('None')
161+
162+
@mock.patch.object(requests, 'request')
163+
def test_call_success(self, requests):
164+
""" It should reteurn result on success response """
165+
requests().json.return_value = {'success': True,
166+
'result': 'result'}
167+
res = self.cfssl.call(None)
168+
self.assertEqual(res, 'result')
169+
170+
if __name__ == '__main__':
171+
unittest.main()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
'author_email': 'support@laslabs.com',
1515
'description': 'This library will allow you to interact with CFSSL '
1616
'using Python.',
17-
'url': 'https://github.com/laslabs/cfssl-py',
17+
'url': 'https://github.com/laslabs/Python-CFSSL',
1818
'license': 'MIT',
1919
'classifiers': [
2020
'Development Status :: 4 - Beta',

tests.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@
33
# License MIT (https://opensource.org/licenses/MIT).
44

55
from setuptools import Command
6-
7-
try:
8-
from xmlrunner import XMLTestRunner
9-
from unittest import TestLoader
10-
except ImportError:
11-
pass
6+
from unittest import TestLoader, TextTestRunner
127

138

149
class FailTestException(Exception):
@@ -22,8 +17,6 @@ class Tests(Command):
2217
MODULE_NAMES = [
2318
'cfssl',
2419
]
25-
TEST_RESULTS = '_results'
26-
COVERAGE_RESULTS = 'coverage.xml'
2720
user_options = [] # < For Command API compatibility
2821

2922
def initialize_options(self, ):
@@ -35,7 +28,7 @@ def finalize_options(self, ):
3528
def run(self, ):
3629
loader = TestLoader()
3730
tests = loader.discover('.', 'test_*.py')
38-
t = XMLTestRunner(verbosity=1, output=self.TEST_RESULTS)
31+
t = TextTestRunner(verbosity=1)
3932
res = t.run(tests)
4033
if not res.wasSuccessful():
4134
raise FailTestException()

0 commit comments

Comments
 (0)