Skip to content

Commit f21f822

Browse files
committed
fix runtime smoke sudo-owned outputs
1 parent 0a2f6de commit f21f822

7 files changed

Lines changed: 26 additions & 5 deletions

File tree

docs/plugins/generated.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2631,6 +2631,8 @@ Run SQLite queries or statements from the controller.
26312631
| `output` | no | `string` | `rows` | Database output format: rows, scalar, json or none. |
26322632
| `fetch` | no | `string` | `all` | Database fetch mode: all, one or none. |
26332633
| `commit` | no | `boolean` | `True` | Commit the database transaction on success; false rolls it back. |
2634+
| `path` | no | `path` | | Remote or local path, depending on the plugin. |
2635+
| `database` | no | `path` | | SQLite database path or database name, depending on the plugin. |
26342636

26352637
Result fields:
26362638

src/automax/plugins/backup.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ def _checksum_cmd(path: str, params: Dict[str, Any]) -> str:
2222
return "true"
2323
if checksum != "sha256":
2424
raise PluginValidationError("checksum must be sha256 or none")
25+
if bool(params.get("sudo", True)):
26+
return f"sudo -n sha256sum {quote(path)} | sudo -n tee {quote(path + '.sha256')} >/dev/null"
2527
return f"sha256sum {quote(path)} > {quote(path + '.sha256')}"
2628

2729

@@ -111,7 +113,7 @@ def manual_commands(self, params: Dict[str, Any], context: ExecutionContext) ->
111113
sudo = _sudo(params)
112114
commands = [f"test -e {quote(src)}"]
113115
if bool(params.get("backup", True)):
114-
commands.append(f"test ! -e {quote(dest)} || {sudo}cp -a {quote(dest)} {quote(dest + str(params.get('backup_suffix', '.pre-restore')))}")
116+
commands.append(f"if test -e {quote(dest)}; then {sudo}cp -a {quote(dest)} {quote(dest + str(params.get('backup_suffix', '.pre-restore')))}; fi")
115117
if bool(params.get("archive", False)):
116118
commands.extend([f"{sudo}mkdir -p {quote(dest)}", f"{sudo}tar -xf {quote(src)} -C {quote(dest)}"])
117119
else:
@@ -179,7 +181,8 @@ def manual_commands(self, params: Dict[str, Any], context: ExecutionContext) ->
179181
find_paths = " ".join(quote(str(item)) for item in paths)
180182
checksum_command = ""
181183
if bool(params.get("content_checksums", True)):
182-
checksum_command = " | while IFS= read -r file; do sha256sum \"$file\"; done"
184+
checksum_tool = f"{sudo}sha256sum"
185+
checksum_command = f" | while IFS= read -r file; do {checksum_tool} \"$file\"; done"
183186
manifest_cmd = (
184187
f"cd {quote(root)} && "
185188
f"find {find_paths} -type f -print | LC_ALL=C sort{checksum_command}"

src/automax/plugins/db/sqlite.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class DbSqliteQueryPlugin(DatabaseQueryPlugin):
1919

2020
name = "db.sqlite.query"
2121
description = "Run SQLite queries or statements from the controller."
22+
optional_params = DatabaseQueryPlugin.optional_params + ("path", "database")
2223

2324
def validate(self, params: Dict[str, Any]) -> None:
2425
super().validate(params)

src/automax/plugins/manual_preview.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ def fallback_manual_commands(plugin_name: str, params: Dict[str, Any], context:
116116
if plugin_name.startswith("db.") and plugin_name.endswith(".query"):
117117
conn = _db_connection(params)
118118
if plugin_name == "db.sqlite.query":
119-
return [f"sqlite3 {_q(conn.get('path', params.get('path', 'database.sqlite')))} '{_db_query(params)};'"]
119+
database = conn.get("path") or conn.get("database") or params.get("path") or params.get("database") or "database.sqlite"
120+
return [f"sqlite3 {_q(database)} '{_db_query(params)};'"]
120121
if plugin_name == "db.postgres.query":
121122
return [f"PGPASSWORD=*** psql -h {_q(conn.get('host', 'localhost'))} -U {_q(conn.get('user', 'postgres'))} -d {_q(conn.get('database', 'postgres'))} -c '{_db_query(params)};'"]
122123
if plugin_name == "db.mysql.query":

src/automax/plugins/metadata.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
"untrusted": {"type": "path", "description": "Untrusted intermediate certificate chain file."},
132132
"ca_file": {"type": "path", "description": "CA bundle file path."},
133133
"config": {"type": "path", "description": "OpenSSL configuration file path."},
134+
"database": {"type": "path", "description": "SQLite database path or database name, depending on the plugin."},
134135
"command": {"type": "string", "description": "Command line to execute."},
135136
"comment": {"type": "string", "description": "User account comment or GECOS field."},
136137
"commit": {"type": "boolean", "default": True, "description": "Commit the database transaction on success; false rolls it back."},

src/automax/plugins/ssh_ops.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,10 @@ def manual_commands(self, params: Dict[str, Any], context: ExecutionContext) ->
206206
command = f"{_sudo(params)}ssh-keygen -y -f {quote(params['path'])}"
207207
if not params.get("dest"):
208208
return [command]
209-
redirect = ">" if bool(params.get("overwrite", False)) else ">"
210209
guard = "" if bool(params.get("overwrite", False)) else f"test ! -e {quote(params['dest'])} && "
211-
return [f"{guard}{command} {redirect} {quote(params['dest'])}"]
210+
if bool(params.get("sudo", True)):
211+
return [f"{guard}{command} | sudo -n tee {quote(params['dest'])} >/dev/null"]
212+
return [f"{guard}{command} > {quote(params['dest'])}"]
212213

213214
def execute(self, params: Dict[str, Any], context: ExecutionContext) -> PluginResult:
214215
rc, out, err = exec_remote(context, self.manual_commands(params, context)[0])

tests/test_next_engine.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ def test_sqlite_database_plugin_executes_transactional_statements(tmp_path: Path
744744
assert select.ok, select.stderr
745745
assert select.data["scalar"] == "automax"
746746
assert select.stdout == "automax"
747+
assert plugin.manual_commands({"database": str(database), "query": "SELECT 1"}, context)[0].startswith(f"sqlite3 {database}")
747748

748749

749750
def test_database_plugins_validate_job_yaml(tmp_path: Path):
@@ -4233,6 +4234,9 @@ def test_ssh_security_plugins_render_manual_commands():
42334234

42344235
assert "ssh-keygen -lf" in registry.get("ssh.fingerprint").manual_commands({"path": "/tmp/id.pub", "sudo": False}, context)[0]
42354236
assert "ssh-keygen -y" in registry.get("ssh.public_key").manual_commands({"path": "/tmp/id", "sudo": False}, context)[0]
4237+
sudo_public_key = registry.get("ssh.public_key").manual_commands({"path": "/tmp/id", "dest": "/root/id.pub"}, context)[0]
4238+
assert "ssh-keygen -y" in sudo_public_key
4239+
assert "| sudo -n tee /root/id.pub >/dev/null" in sudo_public_key
42364240
assert "ssh-keygen -A" in registry.get("ssh.host_keygen").manual_commands({"sudo": False}, context)[0]
42374241
assert "authorized_keys" in registry.get("ssh.authorized_key_absent").manual_commands({"user": "deploy", "key": "ssh-ed25519 AAA demo", "sudo": False}, context)[0]
42384242
assert "sshd -t" in registry.get("sshd.validate").manual_commands({}, context)[0]
@@ -4353,6 +4357,14 @@ def test_backup_completeness_plugins_render_manual_commands():
43534357
assert "find . -type f" in manifest
43544358
assert "tee /var/backups/manifest.txt" in manifest
43554359

4360+
sudo_manifest = registry.get("backup.manifest").manual_commands({"root": "/var/backups", "dest": "/var/backups/manifest.txt"}, context)[0]
4361+
assert "sudo -n sha256sum" in sudo_manifest
4362+
assert "sudo -n tee /var/backups/manifest.txt.sha256 >/dev/null" in sudo_manifest
4363+
4364+
restore = registry.get("backup.restore").manual_commands({"src": "/var/backups/file.txt", "dest": "/srv/file.txt", "confirm": True}, context)[0]
4365+
assert "if test -e /srv/file.txt; then sudo -n cp -a /srv/file.txt /srv/file.txt.pre-restore; fi" in restore
4366+
assert "sudo -n cp -a /var/backups/file.txt /srv/file.txt" in restore
4367+
43564368
try:
43574369
registry.get("backup.prune").manual_commands({"path": "/var/backups", "keep": 7}, context)
43584370
except PluginValidationError as exc:

0 commit comments

Comments
 (0)