Repository navigation
2.0.1: scan a journal after a shell command changes it #2
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 |
|---|---|---|
| @@ -1 +1 @@ | ||
| 2.0.0 | ||
| 2.0.1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,7 +57,7 @@ | |
| except ImportError: # not POSIX: run without the lock | ||
| fcntl = None | ||
|
|
||
| VERSION = '2.0.0' | ||
| VERSION = '2.0.1' | ||
| SKIP_OK = '<!-- journal-secrets-ok -->' | ||
| NAME = re.compile(r'^(\d{4}-\d\d-\d\d-(?:\d{4}-)?[A-Za-z0-9._-]+\.md)$') # HHMM is optional: older journals lack it | ||
| CLOSED = {'DONE', 'COMPLETE', 'COMPLETED', 'DELIVERED', 'CLOSED', 'SUPERSEDED', 'ABANDONED', '?'} # anything else is open | ||
|
|
@@ -1005,8 +1005,21 @@ def on_post_tool(ctx, inp): | |
| lease['size_warned'] = free[-1] | ||
| notes.append(f"{ctx.show(free[-1])} is {c['bytes'] // 1024} KB. Finish this update, then continue the " | ||
| f"work in a new journal whose header says '**Continues:** {ctx.show(free[-1])}'.") | ||
| leaks = [] | ||
| if cmd is not None and ctx.secrets != 'off': | ||
| # A shell write can carry a credential PreToolUse never saw (`cat secret > "$F"`): scan the journal itself. | ||
| for jn in names: | ||
| hits = scan_secrets(read(ctx.jpath(jn))) | ||
| if hits: | ||
| leaks.append((jn, hits)) | ||
|
Comment on lines
+1011
to
+1014
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.
When an opaque shell command modifies three or more journals, Useful? React with 👍 / 👎. |
||
| if ctx.secrets == 'deny': | ||
| lease['leaked'] = sorted(set(lease.get('leaked') or []) | {jn for jn, _ in leaks}) | ||
| ctx.save_lease(lease) | ||
| if names and ctx.secrets == 'warn': | ||
| for jn, hits in leaks: | ||
| ctx.trace(ev='secret-after-write', sid=lease['sid'], journal=jn, kinds=[h[1] for h in hits]) | ||
| notes.append(f"{ctx.show(jn)} now contains credential-shaped content ({fmt_hits(hits)}). Remove the value " | ||
| "now and write where the secret lives instead; journals are committed and shared.") | ||
| if names and cmd is None and ctx.secrets == 'warn': | ||
| hits = scan_secrets(tool_text(tool, ti)) | ||
| if hits: | ||
| ctx.trace(ev='secret-warning', sid=lease['sid'], journal=names[-1], kinds=[h[1] for h in hits]) | ||
|
|
@@ -1047,6 +1060,17 @@ def on_stop(ctx, inp): | |
| nudge = None | ||
| with ctx.lock(): | ||
| lease = get_lease(ctx, inp) | ||
| leaks = [(jn, scan_secrets(read(ctx.jpath(jn)))) for jn in lease.get('leaked') or []] | ||
| leaks = [(jn, h) for jn, h in leaks if h] | ||
| if lease.get('leaked'): | ||
| lease['leaked'] = [jn for jn, _ in leaks] | ||
| if leaks and not inp.get('stop_hook_active'): | ||
| ctx.save_lease(lease) | ||
| ctx.trace(ev='stop', sid=sid, result='secret', journal=leaks[-1][0]) | ||
| return {'decision': 'block', 'reason': 'SESSION-JOURNAL-SECRETS: ' + '; '.join( | ||
|
Comment on lines
+1067
to
+1070
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.
After the first Stop block, the runtime's next Stop invocation has Useful? React with 👍 / 👎. |
||
| f'{ctx.show(jn)} still contains credential-shaped content ({fmt_hits(h)})' for jn, h in leaks) + | ||
| '. Remove the values and write where each secret lives (a vault entry, an env var name, or ' | ||
| '<redacted>). Mark a line <!-- journal-secrets-ok --> only after a human has checked it.'} | ||
| key = turn_key(inp, lease, fallback=f['turn_start_ts']) | ||
| t0 = iso_epoch(f['turn_start_ts'] or '') - 2 | ||
| turn = turn_record(lease, key) | ||
|
|
||
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.
With the installed Bash hooks, a command such as
./update-journal.shor. /tmp/vars; cat /tmp/notes > "$F"can modify a journal without containing the literal journal-directory name or matching the landing regex.run_hook()then exits throughtool_may_matter()for both PreToolUse and PostToolUse, so no pending timestamp is recorded and this new scan never runs; the credential remains and Stop has noleakedentry. Route opaque Bash calls through the before/after detection path as well.Useful? React with 👍 / 👎.