Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion changelogs/2026-01-29_19-47-44.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
- **Documentation Updates**: The `README.md` and `docs/env-generation.md` have been updated to reflect the new environment variable management approach and the removal of the `env_blob` input.

### Removed
- The `env_blob` input from `action.yml` has been removed. Its functionality is now superseded by the enhanced capabilities of the `ENV` secret for passing raw environment variable blocks and templating.
- The `env_blob` input from `action.yml` has been removed. Its functionality is now superseded by the enhanced capabilities of the `ENV` secret for passing raw environment variable blocks and templating.
2 changes: 1 addition & 1 deletion changelogs/2026-01-29_19-48-25.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
- **Refined Secret Parsing**: Further internal refinements to the environment variable parsing logic improve robustness when handling various formats and merging into base templates, ensuring more reliable processing of complex environment variable strings.

### Removed
- The `env_blob` input and its associated functionality for bulk secret injection have been removed. Users should now leverage the `ENV` secret for providing raw blocks of variables that serve as a base template for generated environment files.
- The `env_blob` input and its associated functionality for bulk secret injection have been removed. Users should now leverage the `ENV` secret for providing raw blocks of variables that serve as a base template for generated environment files.
15 changes: 15 additions & 0 deletions changelogs/2026-01-29_20-04-22.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog

## [Unreleased]

### Added
- **`use_shell_profile` Option for Remote Commands**: Introduced a new `use_shell_profile` parameter in the `run_command` utility, allowing users to execute commands on remote hosts without sourcing the user's shell profile. This can be used for commands that do not require shell environment setup, potentially improving performance.

### Changed
- **Optimized Environment File Creation**: The process of creating and managing environment files on remote hosts has been significantly optimized. Multiple operations (directory creation, file content writing, and permissions setting) are now batched into a single SSH command, and shell profile loading is skipped for these specific tasks, leading to faster and more efficient environment file deployments.
- **Enhanced `ENV` Secret Functionality**: The `ENV` secret now offers more robust capabilities for passing raw blocks of environment variables and supports advanced templating, providing a more powerful and flexible method for managing deployment configurations.
- **Improved Environment Variable Parsing**: Internal parsing logic for environment variables has been refined to enhance robustness when handling diverse formats and merging them into base templates, ensuring more reliable processing of complex environment strings.
- **Documentation Updates**: The `README.md` and `docs/env-generation.md` have been updated to reflect the new environment variable management approach and the removal of the `env_blob` input.

### Removed
- The `env_blob` input from `action.yml` has been removed. Its functionality is now superseded by the enhanced capabilities of the `ENV` secret for passing raw environment variable blocks and templating.
12 changes: 7 additions & 5 deletions src/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ def setup_ssh_key():
os.chmod(config.SSH_KEY_PATH, 0o600)


def run_command(conn, command, force_sudo=False):
"""
Helper function to run commands with optional sudo support.
"""
def run_command(conn, command: str, force_sudo: bool = False, use_shell_profile: bool = True):
"""Run a command on the remote host with environment setup and sudo support"""
use_sudo_for_this = config.USE_SUDO or force_sudo

if not use_sudo_for_this:
if not use_sudo_for_this and not use_shell_profile:
return conn.run(command, warn=False)

if not use_shell_profile:
# Just sudo without the expensive profile loading
return conn.run(f"sudo {command}", warn=False)

if config.REMOTE_USER == "root":
home_dir = "/root"
else:
Expand Down
14 changes: 8 additions & 6 deletions src/env_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,14 +416,16 @@ def create_env_file(conn, file_path: str, env_content: str) -> None:
if not env_content:
return
dir_path = os.path.dirname(file_path)
if dir_path and dir_path != file_path:
# Only mkdir, skip chmod on directory to avoid permission errors
run_command(conn, f"mkdir -p {dir_path}")

# Use base64 to avoid shell character/newline mangling issues
encoded = base64.b64encode(env_content.encode("utf-8")).decode("utf-8")
run_command(conn, f"echo '{encoded}' | base64 -d | tee \"{file_path}\" > /dev/null")
run_command(conn, f'chmod 600 "{file_path}"')

# Batch commands into one SSH round-trip and skip expensive shell profile sourcing
batch_cmd = (
f'mkdir -p "{dir_path}" && '
f'echo "{encoded}" | base64 -d | tee "{file_path}" > /dev/null && '
f'chmod 600 "{file_path}"'
)
run_command(conn, batch_cmd, use_shell_profile=False)


def generate_env_files(conn) -> None:
Expand Down
9 changes: 9 additions & 0 deletions tests/unit/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ def test_run_command_sudo_wrapping(mock_conn, monkeypatch):
assert "source /home/deploy/.bashrc" in call_args


def test_run_command_no_profile(mock_conn, monkeypatch):
monkeypatch.setattr(config, "USE_SUDO", True)
run_command(mock_conn, "simple-cmd", use_shell_profile=False)

call_args = mock_conn.run.call_args[0][0]
assert call_args == "sudo simple-cmd"
assert "bash -l -c" not in call_args


def test_run_command_password_sudo(mock_conn, monkeypatch):
monkeypatch.setattr(config, "USE_SUDO", True)
monkeypatch.setattr(config, "REMOTE_PASSWORD", "mypass")
Expand Down
19 changes: 10 additions & 9 deletions tests/unit/test_env_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,16 @@ def test_root_mega_file_creation(mock_conn, monkeypatch):
def test_heredoc_escaping(mock_conn):
# We need to mock run_command because create_env_file now uses it
with patch("src.env_manager.run_command") as mock_run:
create_env_file(mock_conn, ".env", "PORT=3000\nDEBUG=true")

# Check that it was called with base64 encoded content
found_base64_tee = False
for call in mock_run.call_args_list:
cmd = call[0][1]
if "base64 -d" in cmd and "tee" in cmd:
found_base64_tee = True
assert found_base64_tee
create_env_file(mock_conn, "/testing/.env", "PORT=3000\nDEBUG=true")

# Check that it was called with a BATCHED command
assert mock_run.call_count == 1
cmd = mock_run.call_args[0][1]
assert "mkdir -p" in cmd
assert "echo" in cmd
assert "chmod 600" in cmd
assert "base64 -d" in cmd
assert mock_run.call_args[1].get("use_shell_profile") is False


def test_mixed_blob_and_raw_bucketing(mocker):
Expand Down