Skip to content

[spark-compete wave 5] security cross-cut (stacked) - #307

Merged
vibeforge1111 merged 16 commits into
masterfrom
spark-compete/wave5-security-crosscut
Jun 26, 2026
Merged

[spark-compete wave 5] security cross-cut (stacked)#307
vibeforge1111 merged 16 commits into
masterfrom
spark-compete/wave5-security-crosscut

Conversation

@vibeforge1111

Copy link
Copy Markdown
Owner

Spark Compete — Wave 5 (security cross-cut), stacked on spark-compete/wave4-memory-persona-voice

Highest-value security set. Wave-5 delta only.

Commits

On-merge points

ifeoluwaaj 9 · jumperz11 5

Verified: proportionate diff, no churn, no conflict markers. Compiles / tests green. Draft — gated on CI + approval.

🤖 Generated with Claude Code

Meta Alchemist and others added 16 commits June 24, 2026 13:18
registry.py DEFAULT_LAB_PATH hardcoded ~/Desktop/spark-personality-chip-labs/personalities,
which breaks installs that don't have the lab checked out on the Desktop. Switch the default
to the platform-safe ~/.spark/spark-personality-chip-labs/personalities location, consistent
with the search paths already prioritized in chip_loader.DEFAULT_CHIP_LAB_PATHS.

Narrowed from PR #28: the chip_loader.py hunk was dropped because HEAD already prioritizes
~/.spark/modules/... and ~/.spark/... ahead of Desktop and uses the stronger guard
'spark-personality-chip-labs' in path.parts (a better impl than the PR's 'in str(path)').
Only the still-unfixed registry.py one-line default is landed here.

Co-authored-by: johncrossu <johncrossu@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The secret-exfiltration guard used \b before the alternation, but \b does
not match between a non-word char (.) and a word char in '.env', so
'curl ... .env' slipped past. Replace the leading \b with a (?<!\w)
look-behind so the dot-prefixed token matches.

PR #291

Co-authored-by: ifeoluwaaj@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t stderr

PR #295 (adopt): wrap subprocess.run in try/except so a missing codex
binary (FileNotFoundError) or an exceeded budget (TimeoutExpired) surface
as an actionable RuntimeError that preserves the operator's next move,
instead of a raw stack trace.

PR #296 (adjust): redact the raw stderr from the non-zero-exit RuntimeError
(keep rc for triage, drop the stderr payload that can carry internal paths
or prompt fragments). Per maintainer note, the tautological packet test
(re-implemented the message, never imported codex_provider) was discarded;
replaced with tests/test_codex_exec_stderr.py exercising the real
call_codex redaction path via a monkeypatched subprocess.run.

PR #295
PR #296

Co-authored-by: 4gjnbzb4zf-sudo@users.noreply.github.com
Co-authored-by: TALLSOME24@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR #276 (adopt): open state.db via 'file:...?mode=ro' URI so the probe
builder can never accidentally mutate SIB's authoritative state (the
user_instructions / personality_observations tables).

PR #297 (adjust): redact sib_home from the _open_state FileNotFoundError
('State database not found'). Per maintainer note, the tautological packet
test (re-implemented the message, never imported memory_grounded) was
discarded; replaced with tests/test_memory_grounded_path.py exercising the
real _open_state on a directory with no state.db.

PR #276
PR #297

Co-authored-by: 4gjnbzb4zf-sudo@users.noreply.github.com
Co-authored-by: TALLSOME24@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Consolidated path-redaction across the character runtime's FileNotFoundError /
ValueError messages so callers no longer learn the internal directory layout.

PR #287 (Esc1200, adopt): drop the full path from critic.load_critic and
the base-chip YAML filename from registry.promote_evolved_persona_to_chip_lab.
PR #286 (Esc1200, adjust; same-author same-concern as #287 -> one band):
drop the search-path list from chip_loader.load_chip_by_id and replace the
absolute artifact paths in persona.set_latest_persona_version / load_persona
with the bare filename. Per maintainer note, also redact
persona.load_persona_from_path (line 203) to the filename for consistency;
the chip id / artifact filename are retained because they aid debugging.
PR #298 (TALLSOME24, adjust): set_latest_persona_version line redaction.
Per maintainer note the tautological packet test (re-implemented the message,
never imported persona) was discarded; replaced with
tests/test_persona_artifact_path.py exercising the real
set_latest_persona_version against a missing artifact.

The bundled packet-chip-loader-path-leak.json from #286 was excluded.

PR #287
PR #286
PR #298

Co-authored-by: Esc1200@users.noreply.github.com
Co-authored-by: TALLSOME24@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…inuous_eval

Replace the two traceback.print_exc() calls in the continuous_eval loop with
module-logger .exception() calls so failures land in structured logs (with the
provider/context) rather than raw stderr dumps.

PR #285

Co-authored-by: Esc1200@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
find_lowest_tier seeded weakest at (None, 1.0, 0), so when every eligible
axis sits at the 1.0 ceiling the strict '< 1.0' comparison never fired and
no tier was returned. Seed at (None, inf, 0) so a perfect-1.0 tier still
qualifies as the weakest when all eligible axes tie at the ceiling.

PR #267

Co-authored-by: 4gjnbzb4zf-sudo@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…md found

When find_latest_persona has no persona.vN.md to load, the bare 'No
persona.vN.md artifacts found.' gave the operator nowhere to look. Name the
ARTIFACTS_DIR it searched and tell them to seed persona.v1.md there (or
override ARTIFACTS_DIR), in both evolve.py and evolve_persona.py.

PR #299

Co-authored-by: 4gjnbzb4zf-sudo@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nary

PR #290 (adjust). Per maintainer note, landed ONLY the reliability/safety core:
- full_pulse.py: wrap score_persona in try/except so a T1 scorer failure
  records an error row and continues instead of crashing the daemon.
- codex_provider._default_codex_binary: when CODEX_PATH / SPARK_CODEX_PATH is
  set, expanduser + isfile-validate it (raise a clear FileNotFoundError)
  rather than blindly returning the string for execution.

REVERTED (not applied): the two '@master' -> '@11c1d2da...' git-URL pins in
evals/auto_loop.py and evals/lowest_tier_watch.py. Hardcoding this PR's own
head commit into the self-evolution consumer-refresh loop would freeze
auto-update and go stale on the next commit (a regression). Both URLs remain
pinned to @master.

PR #290

Co-authored-by: ifeoluwaaj@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n not-found

PR #6 (resurrect_adopt): make validate_chip_yaml_spec errors actionable -
each type/shape failure now reports the offending type (got X) and a small
inline YAML example, plus a pointer to the canonical chip schema doc.

Also refines the #286 redaction of load_chip_by_id's FileNotFoundError: the
full path-list was stripped, but the existing repo test
(test_load_chip_by_id_omits_unavailable_desktop_lab_from_default_paths)
asserts the *active* search-lab basenames stay in the message (while the
unavailable Desktop lab must not). Restore the active-lab basenames (names
only, de-duped/sorted) so the message stays debuggable without leaking the
full filesystem layout.

PR #6

Co-authored-by: 4gjnbzb4zf-sudo@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… example

PR #21 (resurrect_adjust). Per maintainer note the chip_loader.py hunk was a
BROKEN DIFF (unresolved <<<<<<< / ======= / >>>>>>> conflict markers; HEAD
already uses 'except recoverable_load_errors' which supersedes it) and was
discarded. Landed ONLY the memory_grounded.py docstring fix: replace the
embedded 'C:/Users/USER/Desktop/.../tmp-home' and the real
'human:telegram:8319079055' id in the usage example with
'Path.home() / ".spark" / "sib-home"' and a '<your-user-id>' placeholder.

PR #21

Co-authored-by: johncrossu@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ntion)

PR #66 (resurrect_adjust). compare_personas.py returned 1 when the baseline
held, conflating a domain verdict with a process failure. Flip to return 0 so
a completed comparison always exits success; the verdict stays on stdout
(WINS vs holds). Per maintainer note, confirmed no CI / Makefile / docs /
wrapper in the repo branches on the old exit-1 signal, and documented the
exit-0-always contract inline (option a).

PR #66

Co-authored-by: 4gjnbzb4zf-sudo@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…bility)

Follow-up to the #287/#286 path-redaction: PR #287 over-redacted
promote_evolved_persona_to_chip_lab's ValueError to fully generic, but the
repo invariant (test_persona_sidecar_promotion_rejects_malformed_base_yaml)
keeps the offending chip *basename* in the message. The basename is not a
path leak (no surrounding directory) and aids debugging, matching the #286
maintainer guidance that the filename should be retained. Restore
': {base_yaml_path.name}'.

PR #287

Co-authored-by: Esc1200@users.noreply.github.com
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The env-var binary validation from #284 (block arbitrary execution via a
malicious/stale CODEX_PATH / SPARK_CODEX_PATH) landed, but it ran inside
_default_codex_binary() at module import (DEFAULT_CODEX_PATH = ...), so a
stale CODEX_PATH crashed every importer of codex_provider — including eval
drivers that never touch the codex backend.

Split resolution from validation:
- _default_codex_binary() now only resolves (expands ~, picks the platform
  fallback) and never raises, so import is always safe.
- new validate_codex_binary() performs the isfile() check, scoped to an
  explicit env-supplied path, and is invoked at call time in call_codex()
  and codex_available(). Bare PATH lookups ("codex") stay a no-op.

Preserves the security guarantee of #284 (an explicit, non-regular-file
path is still blocked before exec) while removing the import-time crash.
Closes the systemic group with #288/#290 (duplicates).

Co-authored-by: ifeoluwaaj <ifeoluwaaj@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cherry-picks the two adversarial tests from #24 onto the current
test_search_adapter.py. The production sanitizer (prompt_guard +
attach_search_context) and a base sanitization test already exist in
HEAD; these add coverage for multi-result snippet payloads:

- snippets that try to become agent instructions (system-prompt-override
  + instruction-override categories), asserting the raw text is dropped
  and the benign summary survives.
- snippets that request hidden data (secret-exfiltration +
  secret-file-request categories).

Test-only; rebased onto current line numbers, no production change.

Co-authored-by: jumperz11 <jumperz11@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vibeforge1111
vibeforge1111 changed the base branch from spark-compete/wave4-memory-persona-voice to master June 26, 2026 13:18
@vibeforge1111
vibeforge1111 marked this pull request as ready for review June 26, 2026 13:20
@vibeforge1111
vibeforge1111 merged commit 8cad276 into master Jun 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant