commit a3831d5ba913eee52f569cdf61fcac001c8375f6
parent 82216e676fa0f97d8f4887bac551c6e426ff2891
Author: Asher Morgan <asher@ashermorgan.net>
Date: Tue, 8 Sep 2026 09:34:11 -0700
Minor cleanup
Diffstat:
7 files changed, 19 insertions(+), 27 deletions(-)
diff --git a/.editorconfig b/.editorconfig
@@ -5,12 +5,10 @@ root = true
[*]
charset = utf-8
end_of_line = lf
+indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
-
-[*.py]
-indent_size = 4
max_line_length = 80
[*.yml]
diff --git a/aoh/client.py b/aoh/client.py
@@ -22,8 +22,8 @@ PASSWORD_PROMPTS = {
'vault_password': 'Vault password: ',
}
-# How long to sleep after receiving an empty responses
-WAIT_INTERVAL = 0.1
+# Interval on which to poll the server when there's nothing to do, in seconds
+POLL_INTERVAL = 0.1
class ClientError(Exception):
@@ -204,7 +204,7 @@ def exec(args, keep_alive_interval, keep_alive_handler):
'stderr': (become_stderr + stderr).decode('latin1'),
}
except Exception as e: # noqa: BLE001
- return { 'err': str(e) }
+ return {'err': str(e)}
def put(args):
@@ -214,9 +214,9 @@ def put(args):
with open(args['dest'], 'wb') as f:
f.write(base64.b64decode(args['data']))
except Exception as e: # noqa: BLE001
- return { 'err': str(e) }
+ return {'err': str(e)}
else:
- return { 'ok': True }
+ return {'ok': True}
def fetch(args):
@@ -228,7 +228,7 @@ def fetch(args):
'data': base64.b64encode(f.read()).decode(),
}
except Exception as e: # noqa: BLE001
- return { 'err': str(e) }
+ return {'err': str(e)}
def runner_loop(runner_url, cookies):
@@ -243,7 +243,7 @@ def runner_loop(runner_url, cookies):
keep_alive_handler = lambda res=res: send_message(
runner_url,
cookies,
- { 'id': res['id'], 'keep-alive': True },
+ {'id': res['id'], 'keep-alive': True},
keep_alive=True
)
req = exec(res['exec'], res['keep-alive-interval'],
@@ -257,7 +257,7 @@ def runner_loop(runner_url, cookies):
req['id'] = res['id']
else:
req = {}
- time.sleep(WAIT_INTERVAL)
+ time.sleep(POLL_INTERVAL)
def create_runner(playbook, args):
diff --git a/aoh/connection_plugins/aoh.py b/aoh/connection_plugins/aoh.py
@@ -1,6 +1,3 @@
-# Copyright: (c) 2026, Asher Morgan <asher@ashermorgan.net>
-# GNU General Public License v3.0+
-
DOCUMENTATION = """
name: aoh
short_description: Run tasks through an Ansible-over-HTTP (AoH) connection
@@ -159,7 +156,7 @@ class Connection(ConnectionBase):
if not res.get('keep-alive'):
return res
- self._send_message_async({ 'id': id, 'keep-alive': True })
+ self._send_message_async({'id': id, 'keep-alive': True})
def exec_command(self, cmd: str, in_data: bytes | None = None,
@@ -182,7 +179,7 @@ class Connection(ConnectionBase):
'success': self.become.success,
}
- res = self._send_message_sync({ 'exec': msg })
+ res = self._send_message_sync({'exec': msg})
if not all(k in res for k in ['returncode', 'stdout', 'stderr']):
raise AnsibleError('Received invalid AoH EXEC response')
return (
@@ -219,7 +216,7 @@ class Connection(ConnectionBase):
display.vvv(f'FETCH {in_path} TO {out_path}',
host=self._play_context.remote_addr)
- res = self._send_message_sync({ 'fetch': in_path })
+ res = self._send_message_sync({'fetch': in_path})
if 'data' not in res:
raise AnsibleError('Received AoH FETCH response without data')
try:
diff --git a/aoh/playbook.py b/aoh/playbook.py
@@ -6,7 +6,6 @@ _PLAYBOOKS_FILE = os.getenv('AOH_PLAYBOOKS_FILE', 'playbooks.yml')
_PLAYBOOKS_DIR = os.path.dirname(_PLAYBOOKS_FILE)
-
class PlaybookError(Exception):
"""Raised for AoH playbook configuration errors."""
diff --git a/aoh/security.py b/aoh/security.py
@@ -5,8 +5,6 @@ import ansible_runner
import bcrypt
import yaml
-_PASSWORDS_FILE = os.getenv('AOH_PASSWORDS_FILE', 'passwords.yml')
-
_CLI_OPT_WHITELIST = [
# These options should be safe for clients to invoke
'--ask-become-pass', '-K',
@@ -14,7 +12,6 @@ _CLI_OPT_WHITELIST = [
'--ask-vault-password', '--ask-vault-pass', '-J',
'--check', '-C',
'--diff', '-D',
- '--help', '-h',
'--limit', '-l',
'--list-tags',
'--skip-tags',
@@ -25,8 +22,7 @@ _CLI_OPT_WHITELIST = [
]
_CLI_OPT_BLACKLIST = [
- # These options are not supported at all by AoH
- '--step', # Interactive
+ '--step', # Interactive, not supported
]
_CLI_PASSWORD_OPTS = {
@@ -47,6 +43,8 @@ _CONFIG_PASSWORD_OPTS = {
'DEFAULT_BECOME_ASK_PASS': 'become_password',
}
+_PASSWORDS_FILE = os.getenv('AOH_PASSWORDS_FILE', 'passwords.yml')
+
def _get_opts(args):
"""Identify options present in a list of CLI arguments."""
diff --git a/aoh/server.py b/aoh/server.py
@@ -48,10 +48,10 @@ def install():
def new_runner(path):
playbook = get_playbook(path)
if not playbook:
- return { 'err': f'Playbook not found: {path}' }, 400
+ return {'err': f'Playbook not found: {path}'}, 400
if not validate_args(playbook, request.json['args']):
- return { 'err': 'Bad or banned arguments passed.' }, 400
+ return {'err': 'Bad or banned arguments passed.'}, 400
exp_pw_types = get_required_passwords(playbook, request.json['args'])
act_pws = request.json.get('passwords', {})
@@ -64,7 +64,7 @@ def new_runner(path):
}, 401
if not validate_aoh_password(playbook, act_pws.get('aoh_password')):
- return { 'err': 'Incorrect AoH password.' }, 401
+ return {'err': 'Incorrect AoH password.'}, 401
act_pws.pop('aoh_password', None) # Don't pass AoH password on to runner
runner = Runner(playbook, request.json['host'], request.json['args'],
diff --git a/requirements.txt b/requirements.txt
@@ -1,8 +1,8 @@
ansible
ansible_runner
+bcrypt
flask
flask-apscheduler
gunicorn
python-dotenv
pyyaml
-bcrypt