def test_handle_options_randomsource_rejects_invalid(self, capsys): # we can not choose illegal values for source of randomness with pytest.raises(SystemExit): handle_options(['-r', 'not-a-valid-source-name']) out, err = capsys.readouterr() assert out == '' assert "invalid choice" in err
def test_handle_options_wordlist_rejects_invalid(self, capsys): # we can choose only existing wordlists with pytest.raises(SystemExit): handle_options(['-w', 'not-a-valid-wordlist-name']) out, err = capsys.readouterr() assert out == '' assert "invalid choice" in err
def test_handle_options_max(self): options = handle_options([]) assert options.max == 0 options = handle_options(['-m', '0']) assert options.max == 0 options = handle_options(['--max', '0']) assert options.max == 0
def test_handle_options_delimiter(self): # we can set delimiter options = handle_options(['-d', ' ']) assert options.delimiter == ' ' options = handle_options(['--delimiter', ' ']) assert options.delimiter == ' ' options = handle_options(['-d', 'WOW']) assert options.delimiter == 'WOW'
def test_handle_options_randomsource(self): # we can choose the source of randomness source_names = get_random_sources().keys() for name in source_names: options = handle_options(['-r', name]) assert options.randomsource == name options = handle_options(['--randomsource', name]) assert options.randomsource == name
def test_handle_options_delimiter_special(self): # we can set number of special characters to be used as delimiter options = handle_options([]) assert options.delimiter_special == 0 options = handle_options(['-D', '3']) assert options.delimiter_special == 3 options = handle_options(['--delimiter-special', '1']) assert options.delimiter_special == 1
def test_handle_options_wordlist(self, capsys): # we can pick a wordlist wordlist_names = get_wordlist_names() for name in wordlist_names: options = handle_options(['-w', name]) assert options.wordlist == name options = handle_options(['--wordlist', name]) assert options.wordlist == name
def test_handle_options_caps(self): # we can set a flag to tell use of caps options = handle_options([]) assert options.caps is True # default options = handle_options(['-c', ]) assert options.caps is True options = handle_options(['--caps', ]) assert options.caps is True options = handle_options(['--no-caps', ]) assert options.caps is False
def test_handle_options_verbose(self): # we can set verbosity level. options = handle_options([]) assert options.verbose == 0 options = handle_options(['-v', ]) assert options.verbose == 1 options = handle_options(['-vv', ]) assert options.verbose == 2 options = handle_options(['--verbose', ]) assert options.verbose == 1 options = handle_options(['--verbose', '--verbose', ]) assert options.verbose == 2
def test_handle_options_infile(self, tmpdir): # we can give an infile tmpdir.chdir() with open('mywords', 'w') as fd: fd.write('one\ntwo\n') options = handle_options(['mywords', ]) assert options.infile == 'mywords'
def test_get_passphrase_special_delimiter(self): # delimiter_special overrules delemiter options = handle_options(args=[]) options.delimiter = " " options.delimiter_special = 2 phrase = get_passphrase(options) assert " " not in phrase
def test_get_passphrase_specialchars(self): # we can request special chars in passphrases options = handle_options(args=[]) options.specials = 2 phrase = get_passphrase(options) specials = [x for x in phrase if x in SPECIAL_CHARS] # the 2nd special char position might be equal to 1st. assert len(specials) > 0
def test_handle_options_defaults(self): # defaults are correctly set options = handle_options([]) assert options.num == 6 assert options.capitalize is True assert options.specials == 0 assert options.infile is None assert options.version is False assert options.delimiter == ""
def test_handle_options_considers_configfile(self, home_dir): # defaults from a local configfile are respected config_file = home_dir / ".diceware.ini" config_file.write("\n".join([ "[diceware]", "num = 3", "caps = off", "delimiter = my-delim", "" ])) options = handle_options([]) assert options.num == 3 assert options.delimiter == "my-delim" assert options.caps is False
def test_handle_options_defaults(self): # defaults are correctly set options = handle_options([]) assert options.num == 6 assert options.capitalize is True assert options.specials == 0 assert options.infile is None assert options.version is False assert options.delimiter == "" assert options.randomsource == "system" assert options.wordlist == "en_8k"
def test_handle_options_defaults(self): # defaults are correctly set options = handle_options([]) assert options.num == 6 assert options.caps is True assert options.specials == 0 assert options.infile is None assert options.version is False assert options.delimiter == "" assert options.randomsource == "system" assert options.wordlist == "en_securedrop"
def test_handle_options_considers_configfile(self, home_dir): # defaults from a local configfile are respected config_file = home_dir / ".diceware.ini" config_file.write("\n".join( ["[diceware]", "num = 3", "caps = off", "delimiter = my-delim", ""])) options = handle_options([]) assert options.num == 3 assert options.delimiter == "my-delim" assert options.caps is False
def test_handle_options_allows_plugins_updating(self, monkeypatch): # we allow plugins to update our argparser, before being used import diceware class FakePlugin(object): @classmethod def update_argparser(cls, parser): parser.add_argument('--foo', default=2, type=int) return parser monkeypatch.setattr(diceware, 'get_random_sources', lambda: dict(foo=FakePlugin)) options = handle_options([]) assert options.foo == 2
def test_handle_options_allows_plugins_updating(self, monkeypatch): # we allow plugins to update our argparser, before being used import diceware class FakePlugin(object): @classmethod def update_argparser(cls, parser): parser.add_argument('--foo', default=2, type=int) return parser monkeypatch.setattr( diceware, 'get_random_sources', lambda: dict(foo=FakePlugin)) options = handle_options([]) assert options.foo == 2
def get_action(): from_number = request.values.get('From') body = request.values.get('Body', None).lower() resp = MessagingResponse() if body == 'riddikulus': dw = diceware.handle_options(['-w' 'en_securedrop']) passphrase = diceware.get_passphrase(dw) resp.message(passphrase) elif body == 'roll': resp.message( 'Roll 5 dice per word count you wish to return. Two word count example format: 12345 54321.' ) else: numbers = re.findall('\d', body) if any(elem in numbers for elem in blacklist) or len(numbers) % 5 > 0: resp.message( 'Value out of range. Please try again. Send `riddikulus` to get a Diceware generated passphrase. Send `roll` to use dice and send results to perform lookup.' ) else: passphrase = [] dicerolls = [] zipped = zip(*(iter(numbers), ) * 5) number_strings = list(zipped) for nums in number_strings: num_strings = ''.join(map(str, nums)) dicerolls.append(num_strings) for number_set in dicerolls: word_result = wordlist_dict[number_set] passphrase.append(word_result) complete_passphrase = ' '.join(passphrase) resp.message(complete_passphrase) return str(resp)
def test_handle_options(self): # we can get help with pytest.raises(SystemExit) as exc_info: handle_options(['--help']) assert exc_info.value.code == 0
def test_handle_options_version(self): # we can ask for version infos options = handle_options([ '--version', ]) assert options.version is True
def test_get_passphrase_max(self): options = handle_options(args=[]) options.max = 15 phrase = get_passphrase(options) assert len(phrase) == 15
def test_get_passphrase_delimiters(self): # we can set separators options = handle_options(args=[]) options.delimiter = " " phrase = get_passphrase(options) assert " " in phrase
def test_handle_options_caps_conflicting_raises_exc(self): # conflicting caps-settings raise an exception with pytest.raises(SystemExit): handle_options(['--caps', '--no-caps']) with pytest.raises(SystemExit): handle_options(['--no-caps', '--caps'])
def test_get_passphrase_no_capitals(self): # we can turn capitals off options = handle_options(args=[]) options.caps = False phrase = get_passphrase(options) assert phrase.lower() == phrase
def test_handle_options_dice_sides(self): # we can set the number of dice sides. options = handle_options([]) assert options.dice_sides == 6 options = handle_options(['--dice-sides', '21']) assert options.dice_sides == 21
def gen_phrase(length=5): return get_passphrase(handle_options(["-n", str(length)]))
def test_get_passphrase_wordlist_fd(self): # we can pass in an own wordlist options = handle_options(args=[]) options.infile = StringIO("word1\n") phrase = get_passphrase(options) assert "Word1" in phrase
def passphrase(): return diceware.get_passphrase(diceware.handle_options(["--delimiter", "-", "--no-caps"]))
def get_passphrase(): options = diceware.handle_options(['--num', '4']) return diceware.get_passphrase(options)
def test_handle_options_version(self): # we can ask for version infos options = handle_options(['--version', ]) assert options.version is True
def main(interactive): # Get current commit: try: currentCommit = git.Repo(os.getcwd()).head.commit.hexsha except: currentCommit = None tempVars = { 'appObject': 'app', 'appName': 'app', 'mainFile': 'main.py', 'appPort': 80, 'codeDir': '.', 'dependencyFile': 'requirements.txt', 'baseImage': 'python:3-alpine3.12', 'currentCommit': currentCommit[:8] if currentCommit else 'latest', 'baseDir': os.path.basename(os.getcwd()), 'imageWorkDir': '/code', 'userID': 0, 'ports': [], 'dnsName': 'localhost' } tempVars['appName'] = slugify(os.getenv('PROJECT_NAME', 'project')) ##### Main session ##### print('🙌 GEPP Starting!') print('📍 Locating main.py file... ', end='') try: mainFile = get_main() except: print('Could not get main.py, exiting.') import sys sys.exit(1) tempVars['mainFile'] = mainFile if interactive: config = get_interactive_config() # TODO Should use `get_interactive_config` function for rest of this block yesNoValidator = Validator.from_callable( is_yes_or_no, error_message='This input contains non-yes/no', move_cursor_to_end=True) listening = prompt( "Is the app listening additional ports (for exposing metrics, healthchecks etc.)? [Y/n]: ", validator=yesNoValidator) if is_yes(listening): print('Write additional ports following this template:\n\ name: any,\n\ protocol: TCP | UDP\n\ port: number') nameValidator = Validator.from_callable( is_name, error_message= 'This input contains non-alphanumeric characters for name', move_cursor_to_end=True) protocolValidator = Validator.from_callable( is_protocol, error_message='This input must TCP or UDP', move_cursor_to_end=True) protocolCompleter = WordCompleter(['TCP', 'UDP']) portValidator = Validator.from_callable( is_port, error_message='This input must between 1 and 65535', move_cursor_to_end=True) while True: dicewareOpts = diceware.handle_options(args=["-n", "3"]) additionalPortName = prompt( "name: ", validator=nameValidator, default=diceware.get_passphrase(dicewareOpts)) additionalPortProtocol = prompt("protocol: ", validator=protocolValidator, completer=protocolCompleter, default='TCP') additionalPort = prompt("port: ", validator=portValidator) tempVars['ports'].append({ 'name': additionalPortName, 'protocol': additionalPortProtocol, 'port': additionalPort }) print("\n🌸\n") isContinue = prompt("Continue? [Y/n]: ", validator=yesNoValidator) if is_no(isContinue): break else: config = generate_default_config() templates = jinja2.Environment( loader=jinja2.PackageLoader(package_name='main'), autoescape=True) tempVars['ports'].append({ 'name': 'http', 'protocol': 'TCP', 'port': tempVars['appPort'] }) # TODO: remove after testing tempVars['ports'].append({'name': 'api', 'protocol': 'TCP', 'port': 8080}) # Check for Dockerfile and create if not exists check_and_create('Dockerfile', templates, 'Dockerfile.j2', '🐳', vars=tempVars) # Check for .dockerignore file and create if not exists check_and_create('.dockerignore', templates, 'dockerignore.j2', '🐳') # Build Docker image print('🏗 Trying Docker image build... ', end='', flush=True) # TODO: check whether main.py, requirements.txt exists or manually supplied tempVars['imageName'] = build_image(repo=tempVars['appName'], tag=tempVars['currentCommit']) print('☸️ Generating YAMLs for Kubernetes:') create_k8s_dir() check_and_create(f'kubernetes/deployment-{tempVars["appName"]}.yaml', templates, 'deployment.yaml.j2', ' -', vars=tempVars) check_and_create(f'kubernetes/service-{tempVars["appName"]}.yaml', templates, 'service.yaml.j2', ' -', vars=tempVars) check_and_create(f'kubernetes/ingress-{tempVars["appName"]}.yaml', templates, 'ingress.yaml.j2', ' -', vars=tempVars) check_and_create(f'kubernetes/hp-autoscaler-{tempVars["appName"]}.yaml', templates, 'hp-autoscaler.yaml.j2', ' -', vars=tempVars) # k3d cluster create $NAME + k3d kubeconfig get $NAME print('⚓ Creating a test cluster with k3d') create_k3d_cluster(tempVars['appName'], images=[tempVars['imageName']]) # Get exposed port list and print exposedPorts = get_k3d_info(tempVars['appName']) print( f' - Connect to Kubernetes Ingress via HTTP using \033[1mhttp://localhost:{exposedPorts["80"]}\033[0m' ) print( f' - Connect to Kubernetes Ingress via HTTPS using \033[1mhttps://localhost:{exposedPorts["443"]}\033[0m' ) print('🚀 Deploying apps to Kubernetes') deploy_to_k8s(tempVars['appName']) print('📦 Generating Terraform file for Azure Kubernetes Service') generate_terraform(tempVars['appName']) print('Done! ✅')