-
Notifications
You must be signed in to change notification settings - Fork 59
fix: harden cron scripts for secure remote use #305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,6 +14,11 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Configuration: ~/.config/aidevops/cron-jobs.json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Logs: ~/.aidevops/.agent-workspace/cron/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Security: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # - Uses HTTPS by default for remote hosts (non-localhost) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # - Supports basic auth via OPENCODE_SERVER_PASSWORD | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # - SSL verification enabled by default (disable with OPENCODE_INSECURE=1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -25,6 +30,7 @@ readonly CRON_LOG_DIR="$WORKSPACE_DIR/cron" | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readonly SCRIPTS_DIR="$HOME/.aidevops/agents/scripts" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readonly OPENCODE_PORT="${OPENCODE_PORT:-4096}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readonly OPENCODE_HOST="${OPENCODE_HOST:-127.0.0.1}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readonly OPENCODE_INSECURE="${OPENCODE_INSECURE:-}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readonly DEFAULT_TIMEOUT=600 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readonly DEFAULT_MODEL="anthropic/claude-sonnet-4-20250514" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -84,19 +90,53 @@ check_jq() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ####################################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check OpenCode server health | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Determine protocol based on host | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Localhost uses HTTP, remote uses HTTPS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ####################################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| check_server() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local url="http://${OPENCODE_HOST}:${OPENCODE_PORT}/global/health" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local auth_header="" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| get_protocol() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local host="$1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Use HTTP only for localhost/127.0.0.1, HTTPS for everything else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "$host" == "localhost" || "$host" == "127.0.0.1" || "$host" == "::1" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "http" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "https" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ####################################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Build curl arguments array for secure requests | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ####################################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| build_curl_args() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CURL_ARGS=(-sf) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Add authentication if configured | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ -n "${OPENCODE_SERVER_PASSWORD:-}" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local user="${OPENCODE_SERVER_USERNAME:-admin}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auth_header="-u ${user}:${OPENCODE_SERVER_PASSWORD}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CURL_ARGS+=(-u "${user}:${OPENCODE_SERVER_PASSWORD}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # shellcheck disable=SC2086 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if curl -sf $auth_header "$url" &>/dev/null; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Add SSL options for HTTPS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local protocol | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| protocol=$(get_protocol "$OPENCODE_HOST") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "$protocol" == "https" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ -n "$OPENCODE_INSECURE" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Allow insecure connections (self-signed certs) - use with caution | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CURL_ARGS+=(-k) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+109
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function can be improved in two ways:
You will need to update
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ####################################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check OpenCode server health | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ####################################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| check_server() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local protocol | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| protocol=$(get_protocol "$OPENCODE_HOST") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| local url="${protocol}://${OPENCODE_HOST}:${OPENCODE_PORT}/global/health" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| build_curl_args | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if curl "${CURL_ARGS[@]}" "$url" &>/dev/null; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -381,11 +381,39 @@ ls -la ~/.aidevops/.agent-workspace/cron/ | |
|
|
||
| ## Security Considerations | ||
|
|
||
| 1. **Server authentication**: Always use `OPENCODE_SERVER_PASSWORD` for network-exposed servers | ||
| 2. **Task validation**: Jobs only execute pre-defined tasks from `cron-jobs.json` | ||
| 3. **Timeout limits**: All jobs have configurable timeouts to prevent runaway sessions | ||
| 4. **Log rotation**: Old logs are automatically pruned (configurable retention) | ||
| 5. **Credential isolation**: Tasks inherit environment from cron, not from config files | ||
| 1. **HTTPS by default**: Remote hosts (non-localhost) automatically use HTTPS | ||
| 2. **Server authentication**: Always use `OPENCODE_SERVER_PASSWORD` for network-exposed servers | ||
| 3. **SSL verification**: Enabled by default; use `OPENCODE_INSECURE=1` only for self-signed certs | ||
| 4. **Task validation**: Jobs only execute pre-defined tasks from `cron-jobs.json` | ||
| 5. **Timeout limits**: All jobs have configurable timeouts to prevent runaway sessions | ||
| 6. **Log rotation**: Old logs are automatically pruned (configurable retention) | ||
| 7. **Credential isolation**: Tasks inherit environment from cron, not from config files | ||
|
Comment on lines
382
to
+390
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Search for log rotation/pruning implementation
rg -n "logrotate|rotate|rotation|prune|retention" --type-list | head -5Repository: marcusquinn/aidevops Length of output: 453 🏁 Script executed: # Get files matching cron-agent or related automation tools
fd "cron-agent" --type fRepository: marcusquinn/aidevops Length of output: 101 🏁 Script executed: # Read the specific lines from the file to see actual content
cat -n ".agent/tools/automation/cron-agent.md" | sed -n '382,420p'Repository: marcusquinn/aidevops Length of output: 1753 🏁 Script executed: # Search for log rotation/pruning patterns in shell scripts
rg "rotate|prune|retention|logrotate" -g "*.sh"Repository: marcusquinn/aidevops Length of output: 2168 🏁 Script executed: # Check the cron-helper.sh script specifically
fd "cron-helper" --type fRepository: marcusquinn/aidevops Length of output: 93 🏁 Script executed: # Look for any log-related operations
rg "log" -g "*.sh" --type sh -i | grep -E "(rotate|prune|cleanup|rotate|retention|rm.*log)" | head -20Repository: marcusquinn/aidevops Length of output: 2092 🏁 Script executed: # Check the cron-helper.sh file for log rotation implementation
cat ".agent/scripts/cron-helper.sh" | wc -lRepository: marcusquinn/aidevops Length of output: 67 🏁 Script executed: # Search specifically in cron-helper.sh for log-related operations
rg "log|rotate|prune" ".agent/scripts/cron-helper.sh"Repository: marcusquinn/aidevops Length of output: 4088 🏁 Script executed: # Check system-cleanup.sh to see the rotate_logs implementation
cat -n ".agent/scripts/system-cleanup.sh" | grep -A 20 "rotate_logs()"Repository: marcusquinn/aidevops Length of output: 1183 Remove or correct the log rotation claim; add guideline violation flag for inline secrets. The Additionally, the inline bash block (lines 396–407) violates progressive disclosure guidelines and exposes 🤖 Prompt for AI Agents |
||
|
|
||
| ### Remote Server Configuration | ||
|
|
||
| For connecting to a remote OpenCode server: | ||
|
|
||
| ```bash | ||
| # Required: Set server host and authentication | ||
| export OPENCODE_HOST="opencode.example.com" | ||
| export OPENCODE_PORT="4096" | ||
| export OPENCODE_SERVER_PASSWORD="your-secure-password" | ||
|
|
||
| # Optional: For self-signed certificates (not recommended for production) | ||
| export OPENCODE_INSECURE=1 | ||
|
|
||
| # Test connection | ||
| cron-helper.sh status | ||
| ``` | ||
|
|
||
| ### Protocol Selection | ||
|
|
||
| | Host | Protocol | Notes | | ||
| |------|----------|-------| | ||
| | `localhost` | HTTP | Safe for local development | | ||
| | `127.0.0.1` | HTTP | Safe for local development | | ||
| | `::1` | HTTP | IPv6 localhost | | ||
| | Any other host | HTTPS | Encrypted connection required | | ||
|
|
||
|
Comment on lines
+392
to
417
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace inline remote-config snippets with authoritative references. As per coding guidelines: Apply progressive disclosure pattern by using pointers to subagents rather than including inline content in agent documentation. Include code examples only when authoritative; use file:line references to point to actual implementation instead of inline code snippets. 🤖 Prompt for AI Agents |
||
| ## Related Documentation | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid redundant calls to
get_protocolin this function and in each function that calls it (check_server,create_session, etc.),build_curl_argsshould accept the protocol as an argument. This improves efficiency and clarifies the function's dependencies.You will need to update all call sites to pass the protocol, for example:
build_curl_args "$protocol".