Skip to content

v0.9.30-chronode.3: round-two adversarial fixes (graphify admin gate, cooldown CAS, provisioning surfacing) + release - #12

Merged
ChronodeAi merged 11 commits into
mainfrom
hotfix/adversarial-round2
Aug 25, 2026
Merged

v0.9.30-chronode.3: round-two adversarial fixes (graphify admin gate, cooldown CAS, provisioning surfacing) + release#12
ChronodeAi merged 11 commits into
mainfrom
hotfix/adversarial-round2

Conversation

@ChronodeAi

Copy link
Copy Markdown
Owner

Second adversarial round over the shipped wave found our own fixes slipping; this closes them properly:

  • Graphify import (HIGH, redo): engine ignores caller cwd entirely (anchored to daemon cwd); REST route requires ADMIN auth whenever explicit path/cwd is present — capability tokens can no longer reach arbitrary files. Capability callers get the default artifact path only.
  • Provisioning failures surfaced at both silent catch sites (+ lstat ENOENT race).
  • Cooldown token-CAS: per-dispatch claims delete only their own marker — rejected crystallize can no longer unprotect a running pipeline; stale rejections cannot erase newer markers.
  • Boot order restored (help exits before warn/hydration side effects; .env-declared data-dir suppresses spurious legacy warning) and STANDALONE_PERSIST_PATH trim-then-fallback restored.

Release: 0.9.30-chronode.3.

Test plan

vitest 1942/1942 · tsc identical to baseline · full canonical R-13 passed 176/176 · evidence/skills/bundle gates green

…th/cwd on the REST route

Both explicitPath and cwd were client-controlled: {cwd:'/etc',path:'/etc/graph.json'}
passed the resolve-vs-resolve containment check, and a symlinked graph.json escaped
it. The engine now ignores caller cwd entirely and computes the default from
process.cwd(); explicit paths stay constrained (basename + under-daemon-cwd) as
defense in depth. The REST route requires administrative authorization whenever a
request carries path or cwd — same authorizeAdministrativeRequest pattern as
global-scope governance — while capability callers import the default
<daemon-cwd>/graphify-out/graph.json and fail honestly when it is absent.
…T race

The bare catch {} around ensureProjectCapabilitySecret() in connect and
onboarding defeated the fail-loud provisioning guarantee — a failed
provision now writes one stderr line pointing at 'agentmemory doctor' while
keeping the never-block-wiring semantics. An existsSync->lstatSync ENOENT
race (file vanished mid-check) returns the reused:false outcome like the
surrounding unreadable-file path instead of throwing raw.
…aims

Two races in the shared release-on-rejection closure: a rejected
auto-crystallize cleared the marker while consolidate-pipeline still ran,
and an async kv.delete could land after a newer stop wrote a fresh marker,
erasing its debounce. Each dispatch now claims the marker with its own
generateId token right before firing and deletes on rejection only when the
marker still carries that token (compare-and-delete, lock-free). Crystallize
fires first so the heavier pipeline holds the newest claim for most of the
cycle; latency profile unchanged — no locks around dispatch.
…ws hydration

--help/-h now prints and exits right after the --data-dir flag fold, before
the legacy ./data warning and .env hydration, so printing usage no longer
emits a spurious relocation warning. warnOnLegacyDataDir moves after
hydrateProcessEnvFromFile() so an AGENTMEMORY_DATA_DIR declared only in
<data-dir>/.env is folded into the environment first and suppresses the
warning. Worker spawns stay downstream of both (folded env inherited,
unchanged); the pinned iii version's default is hoisted to III_PIN_DEFAULT
so help text needs no hydrated value.
…SIST_PATH

A whitespace-only value was honored verbatim as a relative persist path
instead of falling back to <data-dir>/standalone.json. Trim first, fall
back when empty.
…; record round-two fixes

The 0.9.30-chronode.2 graphify bullet overstated the guarantee ('inside the
requested project cwd') when both path and cwd were client-controlled; it now
states explicit path/cwd imports are ADMIN-only with the daemon-cwd anchor.
Adds bullets for the warnOnLegacyDataDir boot-order fix, the
STANDALONE_PERSIST_PATH trim restoration, the cooldown token-CAS hardening,
and logged capability-provisioning failures.
Same 176 suites (path hash unchanged); content hash moves for
graph-import-scope, graph-import, capability-secret-hardening,
consolidation-lifecycle, and data-dir.
tsdown rebuild rehashes the shared sidecar chunks that pull in
triggers/api.ts, functions/graph-import.ts, triggers/events.ts,
cli/connect/*, and config.ts; import maps updated accordingly.
Source identity rotated: api::graph-import-graphify gained the path/cwd
admin gate in src/triggers/api.ts and connect/onboarding provisioning
gained stderr logging; route count and auth coverage unchanged
(0 missing-auth routes).
@ChronodeAi
ChronodeAi merged commit f6a72a0 into main Aug 25, 2026
4 checks passed
@ChronodeAi
ChronodeAi deleted the hotfix/adversarial-round2 branch August 25, 2026 01:43
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