mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-04 17:18:11 +02:00
v1.55.1.0 fix: telemetry consent accuracy + gstack-slug cache sanitization (#1848)
* fix(gstack-slug): sanitize cached slug before eval The compute and fallback paths filter slug output to [a-zA-Z0-9._-], but a value read straight from ~/.gstack/slug-cache was echoed into eval output unsanitized. A locally-planted cache file could inject shell into eval "$(gstack-slug)". Re-sanitize on every path so the invariant the file header promises actually holds, and heal a poisoned cache on the next write. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(telemetry): accurate consent copy + JSON-safe repo basename The telemetry consent prompt promised "no repo names" while the preamble epilogue records the repo basename in the local skill-usage.jsonl. It is already stripped before any remote upload, so it never left the machine, but the copy was unqualified. Reword it to state repo name is local-only and stripped before upload. Also sanitize the basename to [a-zA-Z0-9._-] before it goes into the hand-built JSON, so a repo directory name containing quotes or newlines can neither break the JSON nor leak a fragment past the regex stripper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(docs): regenerate SKILL.md + ship goldens for telemetry change Generated output of the preceding resolver change: the corrected consent copy and sanitized repo basename now appear in every skill preamble. Golden ship fixtures refreshed to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(telemetry): enforce no-repo-identity-egress invariant Pins the contract that repo/branch identity in the synced skill-usage.jsonl is stripped before the remote POST. Three checks: a floor (the three known fields), coverage (every repo/branch field a producer writes into skill-usage.jsonl is stripped, so a future producer rename can't silently leak), and behavior (runs the actual sed strip expressions over a sample event). Scoped to the synced file, so the local-only timeline branch field is correctly excluded. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(gstack-slug): regression test for cached-slug eval injection Proves a poisoned ~/.gstack/slug-cache file cannot inject shell metacharacters into gstack-slug output (the value consumed by eval). Verified red when the cache-read sanitization is removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: bump version and changelog (v1.55.1.0) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -63,7 +63,7 @@ _QUESTION_TUNING=$(~/.claude/skills/gstack/bin/gstack-config get question_tuning
|
||||
echo "QUESTION_TUNING: $_QUESTION_TUNING"
|
||||
mkdir -p ~/.gstack/analytics
|
||||
if [ "$_TEL" != "off" ]; then
|
||||
echo '{"skill":"qa-only","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
|
||||
echo '{"skill":"qa-only","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(_repo=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null | tr -cd 'a-zA-Z0-9._-'); echo "${_repo:-unknown}")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
|
||||
fi
|
||||
for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do
|
||||
if [ -f "$_PF" ]; then
|
||||
@@ -173,7 +173,7 @@ Only run `open` if yes. Always run `touch`.
|
||||
|
||||
If `TEL_PROMPTED` is `no` AND `LAKE_INTRO` is `yes`: ask telemetry once via AskUserQuestion:
|
||||
|
||||
> Help gstack get better. Share usage data only: skill, duration, crashes, stable device ID. No code, file paths, or repo names.
|
||||
> Help gstack get better. Share usage data only: skill, duration, crashes, stable device ID. No code or file paths. Your repo name is recorded locally only and stripped before any upload.
|
||||
|
||||
Options:
|
||||
- A) Help gstack get better! (recommended)
|
||||
|
||||
Reference in New Issue
Block a user