Skip to content

Commit f6fcf95

Browse files
committed
fix: harden local logging and concept tracking
1 parent 8a943eb commit f6fcf95

5 files changed

Lines changed: 86 additions & 26 deletions

File tree

scripts/lib/log-helpers.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/bash
2+
# CodeSensei — Shared Log Helpers
3+
# Utilities for trimming local logs and redacting sensitive command content.
4+
5+
trim_log_file() {
6+
local file_path="$1"
7+
local max_lines="$2"
8+
9+
if [ ! -f "$file_path" ]; then
10+
return 0
11+
fi
12+
13+
local line_count
14+
line_count=$(wc -l < "$file_path" 2>/dev/null || echo 0)
15+
if [ "$line_count" -gt "$max_lines" ]; then
16+
tail -n "$max_lines" "$file_path" > "${file_path}.tmp" && mv "${file_path}.tmp" "$file_path"
17+
fi
18+
}
19+
20+
redact_sensitive_command() {
21+
local raw_command="$1"
22+
23+
printf '%s' "$raw_command" | \
24+
sed -E \
25+
-e 's/([A-Za-z_][A-Za-z0-9_]*(TOKEN|SECRET|PASSWORD|PASSWD|PWD|API_KEY|APIKEY|ACCESS_KEY|ACCESSKEY|PRIVATE_KEY|COOKIE|SESSION)[A-Za-z0-9_]*=)"[^"]*"/\1"[REDACTED]"/Ig' \
26+
-e "s/([A-Za-z_][A-Za-z0-9_]*(TOKEN|SECRET|PASSWORD|PASSWD|PWD|API_KEY|APIKEY|ACCESS_KEY|ACCESSKEY|PRIVATE_KEY|COOKIE|SESSION)[A-Za-z0-9_]*=)'[^']*'/\\1'[REDACTED]'/Ig" \
27+
-e 's/([A-Za-z_][A-Za-z0-9_]*(TOKEN|SECRET|PASSWORD|PASSWD|PWD|API_KEY|APIKEY|ACCESS_KEY|ACCESSKEY|PRIVATE_KEY|COOKIE|SESSION)[A-Za-z0-9_]*=)[^[:space:]]+/\1[REDACTED]/Ig' \
28+
-e 's/(--?(token|secret|password|pass|api-key|apikey|access-key|accesskey|private-key|authorization|cookie|session)(=|[[:space:]]+))[^[:space:]]+/\1[REDACTED]/Ig' \
29+
-e "s/(Authorization:[[:space:]]*(Bearer|Basic)[[:space:]]+)[^\"'[:space:]]+/\\1[REDACTED]/Ig" \
30+
-e 's#(https?://[^/@[:space:]]+:)[^/@[:space:]]+@#\1[REDACTED]@#g'
31+
}

scripts/session-start.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
99
source "${SCRIPT_DIR}/lib/profile-io.sh"
1010
# shellcheck source=lib/date-compat.sh
1111
source "${SCRIPT_DIR}/lib/date-compat.sh"
12+
# shellcheck source=lib/log-helpers.sh
13+
source "${SCRIPT_DIR}/lib/log-helpers.sh"
1214

1315
LIB_DIR="${SCRIPT_DIR}/lib"
1416
if [ -f "${LIB_DIR}/error-handling.sh" ]; then
@@ -21,6 +23,7 @@ else
2123
fi
2224

2325
SESSION_LOG="${PROFILE_DIR}/sessions.log"
26+
SESSION_LOG_MAX_LINES=500
2427
TODAY=$(date_today)
2528

2629
ensure_profile_dir
@@ -155,6 +158,7 @@ fi
155158
if ! printf '%s %s session_start\n' "$TODAY" "$(date -u +%H:%M:%S)" >> "$SESSION_LOG" 2>&1; then
156159
log_error "$SCRIPT_NAME" "Failed to write to session log: $SESSION_LOG"
157160
fi
161+
trim_log_file "$SESSION_LOG" "$SESSION_LOG_MAX_LINES"
158162

159163
if [ "$NEW_STREAK" -ge 7 ] && [ "$NEW_STREAK" != "$CURRENT_STREAK" ]; then
160164
echo "$NEW_STREAK-day streak! Consistency is the Dojo Way."

scripts/session-stop.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
77

88
# shellcheck source=lib/profile-io.sh
99
source "${SCRIPT_DIR}/lib/profile-io.sh"
10+
# shellcheck source=lib/log-helpers.sh
11+
source "${SCRIPT_DIR}/lib/log-helpers.sh"
1012

1113
LIB_DIR="${SCRIPT_DIR}/lib"
1214
if [ -f "${LIB_DIR}/error-handling.sh" ]; then
@@ -19,6 +21,7 @@ else
1921
fi
2022

2123
SESSION_LOG="${PROFILE_DIR}/sessions.log"
24+
SESSION_LOG_MAX_LINES=500
2225
SESSION_STATE="${PROFILE_DIR}/session-state.json"
2326
TODAY=$(date -u +%Y-%m-%d)
2427

@@ -53,6 +56,7 @@ if ! printf '%s %s session_stop concepts=%s xp=%s belt=%s\n' \
5356
then
5457
log_error "$SCRIPT_NAME" "Failed to write to session log: $SESSION_LOG"
5558
fi
59+
trim_log_file "$SESSION_LOG" "$SESSION_LOG_MAX_LINES"
5660

5761
if ! update_profile '.session_concepts = []'; then
5862
log_error "$SCRIPT_NAME" "Failed clearing session_concepts during session stop"

scripts/track-code-change.sh

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
88

99
# shellcheck source=lib/profile-io.sh
1010
source "${SCRIPT_DIR}/lib/profile-io.sh"
11+
# shellcheck source=lib/log-helpers.sh
12+
source "${SCRIPT_DIR}/lib/log-helpers.sh"
1113

1214
CHANGES_LOG="${PROFILE_DIR}/session-changes.jsonl"
1315
SESSION_STATE="${PROFILE_DIR}/session-state.json"
1416
RATE_LIMIT_INTERVAL=30
1517
SESSION_CAP=12
18+
CHANGES_LOG_MAX_LINES=1000
1619

1720
LIB_DIR="${SCRIPT_DIR}/lib"
1821
if [ -f "${LIB_DIR}/error-handling.sh" ]; then
@@ -78,40 +81,51 @@ case "$EXTENSION" in
7881
*) TECH="other" ;;
7982
esac
8083

84+
TRACKED_CONCEPT="$TECH"
85+
case "$TECH" in
86+
javascript) TRACKED_CONCEPT="js-basics" ;;
87+
react) TRACKED_CONCEPT="react-components" ;;
88+
sql) TRACKED_CONCEPT="sql-basics" ;;
89+
shell) TRACKED_CONCEPT="terminal-navigation" ;;
90+
other) TRACKED_CONCEPT="" ;;
91+
esac
92+
8193
SAFE_FILE_PATH=$(printf '%s' "$FILE_PATH" | sed 's/\\/\\\\/g; s/"/\\"/g')
8294
SAFE_TOOL_NAME=$(printf '%s' "$TOOL_NAME" | sed 's/\\/\\\\/g; s/"/\\"/g')
83-
if ! printf '{"timestamp":"%s","tool":"%s","file":"%s","extension":"%s","tech":"%s"}\n' \
84-
"$TIMESTAMP" "$SAFE_TOOL_NAME" "$SAFE_FILE_PATH" "$EXTENSION" "$TECH" >> "$CHANGES_LOG" 2>&1
95+
SAFE_TRACKED_CONCEPT=$(printf '%s' "$TRACKED_CONCEPT" | sed 's/\\/\\\\/g; s/"/\\"/g')
96+
if ! printf '{"timestamp":"%s","tool":"%s","file":"%s","extension":"%s","tech":"%s","concept":"%s"}\n' \
97+
"$TIMESTAMP" "$SAFE_TOOL_NAME" "$SAFE_FILE_PATH" "$EXTENSION" "$TECH" "$SAFE_TRACKED_CONCEPT" >> "$CHANGES_LOG" 2>&1
8598
then
8699
log_error "$SCRIPT_NAME" "Failed to write to changes log: $CHANGES_LOG"
87100
fi
101+
trim_log_file "$CHANGES_LOG" "$CHANGES_LOG_MAX_LINES"
88102

89103
IS_FIRST_EVER="false"
90-
if [ -f "$PROFILE_FILE" ] && [ "$TECH" != "other" ]; then
91-
ALREADY_IN_SESSION=$(jq --arg tech "$TECH" '.session_concepts | index($tech)' "$PROFILE_FILE" 2>&1)
104+
if [ -f "$PROFILE_FILE" ] && [ -n "$TRACKED_CONCEPT" ]; then
105+
ALREADY_IN_SESSION=$(jq --arg concept "$TRACKED_CONCEPT" '.session_concepts | index($concept)' "$PROFILE_FILE" 2>&1)
92106
if [ $? -ne 0 ]; then
93-
log_error "$SCRIPT_NAME" "jq failed checking session_concepts for $TECH: $ALREADY_IN_SESSION"
107+
log_error "$SCRIPT_NAME" "jq failed checking session_concepts for $TRACKED_CONCEPT: $ALREADY_IN_SESSION"
94108
ALREADY_IN_SESSION="0"
95109
fi
96110

97-
ALREADY_IN_LIFETIME=$(jq --arg tech "$TECH" '.concepts_seen | index($tech)' "$PROFILE_FILE" 2>&1)
111+
ALREADY_IN_LIFETIME=$(jq --arg concept "$TRACKED_CONCEPT" '.concepts_seen | index($concept)' "$PROFILE_FILE" 2>&1)
98112
if [ $? -ne 0 ]; then
99-
log_error "$SCRIPT_NAME" "jq failed checking concepts_seen for $TECH: $ALREADY_IN_LIFETIME"
113+
log_error "$SCRIPT_NAME" "jq failed checking concepts_seen for $TRACKED_CONCEPT: $ALREADY_IN_LIFETIME"
100114
ALREADY_IN_LIFETIME="0"
101115
fi
102116

103117
if [ "$ALREADY_IN_LIFETIME" = "null" ]; then
104118
IS_FIRST_EVER="true"
105-
if ! update_profile --arg tech "$TECH" '
106-
.session_concepts += (if (.session_concepts | index($tech)) == null then [$tech] else [] end) |
107-
.concepts_seen += (if (.concepts_seen | index($tech)) == null then [$tech] else [] end)
119+
if ! update_profile --arg concept "$TRACKED_CONCEPT" '
120+
.session_concepts += (if (.session_concepts | index($concept)) == null then [$concept] else [] end) |
121+
.concepts_seen += (if (.concepts_seen | index($concept)) == null then [$concept] else [] end)
108122
'; then
109-
log_error "$SCRIPT_NAME" "Failed updating profile for first-time technology: $TECH"
123+
log_error "$SCRIPT_NAME" "Failed updating profile for first-time concept: $TRACKED_CONCEPT"
110124
IS_FIRST_EVER="false"
111125
fi
112126
elif [ "$ALREADY_IN_SESSION" = "null" ]; then
113-
if ! update_profile --arg tech "$TECH" '.session_concepts += [$tech]'; then
114-
log_error "$SCRIPT_NAME" "Failed updating session_concepts for technology: $TECH"
127+
if ! update_profile --arg concept "$TRACKED_CONCEPT" '.session_concepts += [$concept]'; then
128+
log_error "$SCRIPT_NAME" "Failed updating session_concepts for concept: $TRACKED_CONCEPT"
115129
fi
116130
fi
117131
fi
@@ -182,8 +196,9 @@ LESSON_ID="${TIMESTAMP}-$(printf '%05d' $$)"
182196
LESSON_FILE="${PENDING_DIR}/${LESSON_ID}.json"
183197
SAFE_FILE_PATH_LESSON=$(printf '%s' "$FILE_PATH" | sed 's/\\/\\\\/g; s/"/\\"/g')
184198
SAFE_TOOL_NAME_LESSON=$(printf '%s' "$TOOL_NAME" | sed 's/\\/\\\\/g; s/"/\\"/g')
185-
if ! printf '{"timestamp":"%s","type":"%s","tech":"%s","file":"%s","tool":"%s","belt":"%s","firstEncounter":%s}\n' \
186-
"$TIMESTAMP" "$LESSON_TYPE" "$TECH" "$SAFE_FILE_PATH_LESSON" "$SAFE_TOOL_NAME_LESSON" "$BELT" "$IS_FIRST_EVER" > "$LESSON_FILE"
199+
SAFE_TRACKED_CONCEPT_LESSON=$(printf '%s' "$TRACKED_CONCEPT" | sed 's/\\/\\\\/g; s/"/\\"/g')
200+
if ! printf '{"timestamp":"%s","type":"%s","tech":"%s","concept":"%s","file":"%s","tool":"%s","belt":"%s","firstEncounter":%s}\n' \
201+
"$TIMESTAMP" "$LESSON_TYPE" "$TECH" "$SAFE_TRACKED_CONCEPT_LESSON" "$SAFE_FILE_PATH_LESSON" "$SAFE_TOOL_NAME_LESSON" "$BELT" "$IS_FIRST_EVER" > "$LESSON_FILE"
187202
then
188203
log_error "$SCRIPT_NAME" "Failed to write pending lesson: $LESSON_FILE"
189204
fi

scripts/track-command.sh

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
88

99
# shellcheck source=lib/profile-io.sh
1010
source "${SCRIPT_DIR}/lib/profile-io.sh"
11+
# shellcheck source=lib/log-helpers.sh
12+
source "${SCRIPT_DIR}/lib/log-helpers.sh"
1113

1214
COMMANDS_LOG="${PROFILE_DIR}/session-commands.jsonl"
1315
SESSION_STATE="${PROFILE_DIR}/session-state.json"
1416
RATE_LIMIT_INTERVAL=30
1517
SESSION_CAP=12
18+
COMMANDS_LOG_MAX_LINES=1000
1619
TRIVIAL_COMMANDS="cd ls pwd clear echo cat which man help exit history alias type file wc whoami hostname uname true false"
1720

1821
LIB_DIR="${SCRIPT_DIR}/lib"
@@ -100,13 +103,16 @@ for trivial in $TRIVIAL_COMMANDS; do
100103
fi
101104
done
102105

106+
SANITIZED_COMMAND=$(redact_sensitive_command "$COMMAND")
107+
103108
if [ "$IS_TRIVIAL" = "true" ]; then
104-
SAFE_LOG_CMD=$(printf '%s' "$COMMAND" | head -c 200 | sed 's/\\/\\\\/g; s/"/\\"/g')
109+
SAFE_LOG_CMD=$(printf '%s' "$SANITIZED_COMMAND" | head -c 200 | sed 's/\\/\\\\/g; s/"/\\"/g')
105110
if ! printf '{"timestamp":"%s","command":"%s","concept":"","skipped":"trivial"}\n' \
106111
"$TIMESTAMP" "$SAFE_LOG_CMD" >> "$COMMANDS_LOG" 2>&1
107112
then
108113
log_error "$SCRIPT_NAME" "Failed to write trivial command log: $COMMANDS_LOG"
109114
fi
115+
trim_log_file "$COMMANDS_LOG" "$COMMANDS_LOG_MAX_LINES"
110116
printf '{}\n'
111117
exit 0
112118
fi
@@ -115,34 +121,34 @@ CONCEPT=""
115121
case "$COMMAND" in
116122
*"npm install"*|*"npm i "*|*"yarn add"*|*"pnpm add"*)
117123
CONCEPT="package-management"
118-
PACKAGE=$(printf '%s' "$COMMAND" | sed -E 's/.*(npm install|npm i|yarn add|pnpm add)[[:space:]]+([^[:space:]]+).*/\2/' | head -1)
119124
;;
120125
*"pip install"*|*"pip3 install"*) CONCEPT="package-management" ;;
121126
*"git "*) CONCEPT="git" ;;
122127
*"docker "*) CONCEPT="docker" ;;
123-
*"curl "*|*"wget "*) CONCEPT="http-requests" ;;
124-
*"mkdir "*|*"touch "*|*"cp "*|*"mv "*|*"rm "*) CONCEPT="file-system" ;;
125-
*"node "*|*"npx "*) CONCEPT="nodejs-runtime" ;;
126-
*"python "*|*"python3 "*) CONCEPT="python-runtime" ;;
127-
*"psql "*|*"mysql "*|*"sqlite3 "*) CONCEPT="database-cli" ;;
128+
*"curl "*|*"wget "*) CONCEPT="rest-apis" ;;
129+
*"mkdir "*|*"touch "*|*"cp "*|*"mv "*|*"rm "*) CONCEPT="terminal-navigation" ;;
130+
*"node "*|*"npx "*) CONCEPT="js-basics" ;;
131+
*"python "*|*"python3 "*) CONCEPT="python" ;;
132+
*"psql "*|*"mysql "*|*"sqlite3 "*) CONCEPT="sql-basics" ;;
128133
*"cd "*|*"ls "*|*"pwd"*) CONCEPT="terminal-navigation" ;;
129-
*"chmod "*|*"chown "*) CONCEPT="permissions" ;;
130-
*"ssh "*|*"scp "*) CONCEPT="remote-access" ;;
134+
*"chmod "*|*"chown "*) CONCEPT="terminal-navigation" ;;
135+
*"ssh "*|*"scp "*) CONCEPT="hosting" ;;
131136
*"env "*|*"export "*) CONCEPT="environment-variables" ;;
132137
*"test "*|*"jest "*|*"vitest "*|*"pytest "*) CONCEPT="testing" ;;
133138
*) CONCEPT="" ;;
134139
esac
135140

136-
CMD_TRUNCATED=$(printf '%s' "$COMMAND" | head -c 200)
141+
CMD_TRUNCATED=$(printf '%s' "$SANITIZED_COMMAND" | head -c 200)
137142
SAFE_LOG_CMD=$(printf '%s' "$CMD_TRUNCATED" | sed 's/\\/\\\\/g; s/"/\\"/g')
138143
SAFE_CONCEPT=$(printf '%s' "$CONCEPT" | sed 's/\\/\\\\/g; s/"/\\"/g')
139144
if ! printf '{"timestamp":"%s","command":"%s","concept":"%s"}\n' \
140145
"$TIMESTAMP" "$SAFE_LOG_CMD" "$SAFE_CONCEPT" >> "$COMMANDS_LOG" 2>&1
141146
then
142147
log_error "$SCRIPT_NAME" "Failed to write to commands log: $COMMANDS_LOG"
143148
fi
149+
trim_log_file "$COMMANDS_LOG" "$COMMANDS_LOG_MAX_LINES"
144150

145-
SAFE_CMD=$(printf '%s' "$COMMAND" | head -c 80 | tr '"' "'" | tr '\\' '/')
151+
SAFE_CMD=$(printf '%s' "$SANITIZED_COMMAND" | head -c 80 | tr '"' "'" | tr '\\' '/')
146152

147153
IS_TEST_RUNNER="false"
148154
case "$COMMAND" in

0 commit comments

Comments
 (0)