Skip to content

Commit e4788ad

Browse files
committed
state: exclude secrets from archives by design
1 parent c0ccf59 commit e4788ad

File tree

4 files changed

+28
-43
lines changed

4 files changed

+28
-43
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ sudo baudbot state restore /tmp/baudbot-state.zip
119119
sudo baudbot start
120120
```
121121

122+
State archives intentionally exclude secrets (`~/.config/.env`, `~/.pi/agent/auth.json`), so reconfigure secrets on the new host.
123+
122124
See [CONFIGURATION.md](CONFIGURATION.md) for required environment variables and secret setup.
123125

124126
## The Slack broker (optional)

bin/state.sh

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# - persistent memory (~/.pi/agent/memory)
66
# - todos (~/.pi/todos)
77
# - local runtime customizations (extensions/skills/subagents/settings)
8-
# - optional secrets (.config/.env and auth.json)
8+
# Secrets are intentionally excluded from state archives.
99

1010
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
1111
# shellcheck source=bin/lib/shell-common.sh
@@ -28,15 +28,10 @@ STATE_PATHS=(
2828
".pi/agent/subagents-state.json"
2929
)
3030

31-
STATE_SECRET_PATHS=(
32-
".config/.env"
33-
".pi/agent/auth.json"
34-
)
35-
3631
usage() {
3732
cat <<'EOF'
3833
Usage:
39-
sudo baudbot state backup [ARCHIVE.zip] [--exclude-secrets] [--force]
34+
sudo baudbot state backup [ARCHIVE.zip] [--force]
4035
sudo baudbot state restore <ARCHIVE.zip> [--restart]
4136
4237
What gets backed up:
@@ -47,11 +42,13 @@ What gets backed up:
4742
- ~/.pi/agent/skills
4843
- ~/.pi/agent/subagents
4944
- ~/.pi/agent/subagents-state.json (if present)
50-
- ~/.config/.env and ~/.pi/agent/auth.json (unless --exclude-secrets)
45+
46+
Never backed up (private by design):
47+
- ~/.config/.env
48+
- ~/.pi/agent/auth.json
5149
5250
Examples:
5351
sudo baudbot state backup /tmp/baudbot-state.zip
54-
sudo baudbot state backup --exclude-secrets
5552
sudo baudbot stop
5653
sudo baudbot state restore /tmp/baudbot-state.zip
5754
sudo baudbot start
@@ -108,7 +105,6 @@ copy_path_if_present() {
108105

109106
write_metadata_file() {
110107
local metadata_file="$1"
111-
local include_secrets="$2"
112108
local now
113109
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
114110

@@ -118,11 +114,11 @@ write_metadata_file() {
118114
fi
119115

120116
require_python3
121-
python3 - "$metadata_file" "$STATE_FORMAT" "$now" "$host_name" "$BAUDBOT_AGENT_USER" "$BAUDBOT_AGENT_HOME" "$include_secrets" <<'PY'
117+
python3 - "$metadata_file" "$STATE_FORMAT" "$now" "$host_name" "$BAUDBOT_AGENT_USER" "$BAUDBOT_AGENT_HOME" <<'PY'
122118
import json
123119
import sys
124120
125-
metadata_path, state_format, created_at, host_name, agent_user, agent_home, include_secrets = sys.argv[1:]
121+
metadata_path, state_format, created_at, host_name, agent_user, agent_home = sys.argv[1:]
126122
127123
with open(metadata_path, "w", encoding="utf-8") as handle:
128124
json.dump(
@@ -132,7 +128,7 @@ with open(metadata_path, "w", encoding="utf-8") as handle:
132128
"host": host_name,
133129
"agent_user": agent_user,
134130
"agent_home": agent_home,
135-
"include_secrets": include_secrets == "1",
131+
"secrets_included": False,
136132
},
137133
handle,
138134
indent=2,
@@ -248,7 +244,7 @@ restore_ownership_if_root() {
248244
return 0
249245
fi
250246

251-
for rel_path in "${STATE_PATHS[@]}" "${STATE_SECRET_PATHS[@]}"; do
247+
for rel_path in "${STATE_PATHS[@]}"; do
252248
if [ -e "$BAUDBOT_AGENT_HOME/$rel_path" ]; then
253249
chown -R "$BAUDBOT_AGENT_USER:$BAUDBOT_AGENT_USER" "$BAUDBOT_AGENT_HOME/$rel_path"
254250
fi
@@ -258,7 +254,6 @@ restore_ownership_if_root() {
258254
cmd_backup() {
259255
local archive_raw=""
260256
local archive_path=""
261-
local include_secrets="1"
262257
local overwrite="0"
263258
local tmp_dir=""
264259
local state_root=""
@@ -267,9 +262,6 @@ cmd_backup() {
267262

268263
while [ "$#" -gt 0 ]; do
269264
case "$1" in
270-
--exclude-secrets)
271-
include_secrets="0"
272-
;;
273265
--force)
274266
overwrite="1"
275267
;;
@@ -312,23 +304,13 @@ cmd_backup() {
312304
copy_path_if_present "$rel_path" "$payload_root"
313305
done
314306

315-
if [ "$include_secrets" = "1" ]; then
316-
for rel_path in "${STATE_SECRET_PATHS[@]}"; do
317-
copy_path_if_present "$rel_path" "$payload_root"
318-
done
319-
fi
320-
321-
write_metadata_file "$state_root/metadata.json" "$include_secrets"
307+
write_metadata_file "$state_root/metadata.json"
322308
create_zip_archive "$state_root" "$archive_path"
323309

324310
chmod 600 "$archive_path" 2>/dev/null || true
325311

326312
echo "✓ state backup created: $archive_path"
327-
if [ "$include_secrets" = "1" ]; then
328-
echo " includes secrets (.config/.env + auth.json)"
329-
else
330-
echo " excludes secrets"
331-
fi
313+
echo " secrets are excluded by design"
332314
}
333315

334316
cmd_restore() {

bin/state.test.sh

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ seed_agent_state() {
6262
printf '{"anthropic":{"type":"oauth"}}\n' > "$agent_home/.pi/agent/auth.json"
6363
}
6464

65-
test_round_trip_with_secrets() {
65+
test_round_trip_excludes_secrets() {
6666
(
6767
set -euo pipefail
6868
local tmp source_home target_home archive
@@ -86,12 +86,12 @@ test_round_trip_with_secrets() {
8686
[ "$(stat -c '%a' "$target_home/.pi/agent/extensions/custom-ext/run.sh")" = "755" ]
8787
grep -q "custom skill" "$target_home/.pi/agent/skills/custom-skill/SKILL.md"
8888
grep -q "enabled" "$target_home/.pi/agent/subagents-state.json"
89-
grep -q "ANTHROPIC_API_KEY" "$target_home/.config/.env"
90-
grep -q "anthropic" "$target_home/.pi/agent/auth.json"
89+
[ ! -f "$target_home/.config/.env" ]
90+
[ ! -f "$target_home/.pi/agent/auth.json" ]
9191
)
9292
}
9393

94-
test_backup_excludes_secrets_flag() {
94+
test_restore_does_not_overwrite_existing_secrets() {
9595
(
9696
set -euo pipefail
9797
local tmp source_home target_home archive
@@ -101,24 +101,26 @@ test_backup_excludes_secrets_flag() {
101101

102102
source_home="$tmp/source-home"
103103
target_home="$tmp/target-home"
104-
archive="$tmp/state-no-secrets.zip"
104+
archive="$tmp/state.zip"
105105

106106
seed_agent_state "$source_home"
107107

108-
run_state "$source_home" backup "$archive" --exclude-secrets
108+
mkdir -p "$target_home/.config"
109+
printf 'ANTHROPIC_API_KEY=keep-existing\n' > "$target_home/.config/.env"
110+
111+
run_state "$source_home" backup "$archive"
109112
run_state "$target_home" restore "$archive"
110113

111-
[ -f "$target_home/.pi/agent/memory/operational.md" ]
112-
[ ! -f "$target_home/.config/.env" ]
114+
grep -q "ANTHROPIC_API_KEY=keep-existing" "$target_home/.config/.env"
113115
[ ! -f "$target_home/.pi/agent/auth.json" ]
114116
)
115117
}
116118

117119
echo "=== state backup/restore tests ==="
118120
echo ""
119121

120-
run_test "round-trip backup/restore includes secrets" test_round_trip_with_secrets
121-
run_test "backup --exclude-secrets omits secret files" test_backup_excludes_secrets_flag
122+
run_test "round-trip backup/restore excludes secrets" test_round_trip_excludes_secrets
123+
run_test "restore keeps existing target secrets" test_restore_does_not_overwrite_existing_secrets
122124

123125
echo ""
124126
echo "=== $PASSED/$TOTAL passed, $FAILED failed ==="

docs/operations.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,9 @@ sudo baudbot start
8181
```
8282

8383
Notes:
84-
- Archive includes `~/.config/.env` and `~/.pi/agent/auth.json` by default.
85-
- Treat archive files as sensitive secrets (store/encrypt/transfer accordingly).
86-
- Use `--exclude-secrets` if you need a shareable archive.
84+
- Archives intentionally exclude secrets (`~/.config/.env`, `~/.pi/agent/auth.json`).
8785
- Restore refuses to run while the service is active.
86+
- Reconfigure secrets on the new host via `sudo baudbot config` / `sudo baudbot env` / `sudo baudbot login`.
8887

8988
## Updating API keys after install
9089

0 commit comments

Comments
 (0)