Task 1.2: introduce a single path resolver so no harness script hardcodes
`.specify/...` scattered across the tree. casan-paths.sh resolves four roots
(HARNESS/STATE/GOVERNANCE/APP) by marker-based walk-up from its own location —
never `git rev-parse` (git root is the repo PARENT here, not the app dir).
- 101 bash scripts/tests: 238 hardcoded `$PROJECT_ROOT/.specify/...` refs rewritten
to CASAN_HARNESS_ROOT (code) / CASAN_STATE_ROOT (logs,state) / CASAN_GOVERNANCE_ROOT.
Sandbox test vars ($WORK/$TP/$FP/$T1_WORK) left untouched.
- Roots are NOT exported: each script/subprocess self-resolves from its own tree,
matching the original per-script semantics and preserving hermetic sandbox isolation
(node casan-step.mjs, copied telemetry/rollback scripts must not inherit real roots).
- Sandbox tests that copy a harness script now also copy casan-paths.sh (its new
sibling dependency): adversarial (verify-audit-chain/verify-tool-audit/rollback) +
track-a (security-check/telemetry-integrity).
- control-plane-settings.json reclassified as STATE (untracked runtime store).
Roots all still resolve to `.specify` in this monolithic layout, so behavior is
unchanged. Full gate: PASS=64 FAIL=0 SKIP=3 (adversarial 44/0, track-a 25/0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- SEC-12: drift-detect adds semantic invariants — negation-flip detection (a dropped
"not" now FAILS despite high char-similarity) + env must-keep patterns.
- SEC-29 (X-05): governance-check audit write fails CLOSED — an unwritable audit log
denies the action and empties the output (no unaudited output).
- SEC-30 (X-06): approval-verify records a one-time-use nonce (sha of token/sig) and
rejects replays (enforced mode / when a nonce ledger is set); dev unchanged.
- SEC-15 (low): typosquat distance<=2 with the levenshtein length-sentinel bug fixed
(no false positives); tool-exec fails closed with no timeout backend in enforced
mode; validate-tool-input now validates nested objects/arrays recursively.
Verify: new SEC suites all green via gate, run-casan4 0-FAIL, adversarial 44/44,
track-c 29/0, h5-approval 12/0, no regressions.
Plan-16 P2 remaining: infra-gated only (SEC-14/22/23/24/25/26).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- SEC-07 (M-08): real approval verification via approval-verify.sh in enforced mode
(CASAN_PROFILE=prod / CASAN_APPROVAL_STRICT=1) for control-plane `set` (sensitive
keys), kill-switch `clear`, and self-improve (inherits control-plane). A bare or
forged approval string is now denied; dev mode stays backward-compatible.
- SEC-10 (M-05): non-spoofable agent identity. tool-registry-gate least-privilege no
longer trusts CASAN_AGENT env in enforced mode (CASAN_IDENTITY_STRICT=1) — the
caller must present a signed token (agent-identity-sign.sh) bound to agent id +
run id, verified against agent-identities.registry. Blocks env spoofing + replay.
Verify: SEC+integrity gate 18/0, run-casan4 0-FAIL, adversarial 44/44 (H2 intact),
control-plane 9/0, h5-approval 12/0, c7-incident 15/0, self-improve 7/0, track-c 29/0.
Plan-16 P0 + P1 now complete; remaining: P2 (SEC-12/13/14/15/22..30).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>