Files
Abhishek Garg c2a1c0a606 fix(aem-agentkit): address PR review findings (security, correctness, tests, CI)
Helper (bin/aem-agentkit-helper):
- op_walk now re-checks resolved-realpath segments against the deny-list,
  closing the in-workspace symlink bypass (e.g. safe-name -> .git/).
- op_write_atomic enforces the SKILL.md allow-list AND a per-segment
  deny-list; helper is now the trust anchor for "no writes outside the
  allow-list" instead of trusting the orchestrating LLM. Adds case-
  insensitive FS collision detection and validate-before-makedirs
  ancestor checks so a workspace symlink cannot redirect mkdir.
- op_open: fail-closed when the TOCTOU re-check is unavailable (returns
  toctouVerified flag); opens the resolved realpath so legitimate
  intra-workspace symlinks (pnpm, yarn workspaces) are no longer
  rejected; bounded buffer read with actual-size diagnostic.
- op_lock: PID-0/negative-PID rejected as stale; PID-reuse defense via
  start-time token; empty/corrupt lock files recovered; stale-lock
  recovery is race-safe.
- op_cleanup_tmp: recovers orphan .tmp left by a crashed write-atomic
  when the .tmp sits at an allow-listed path. Uses bounded walk with
  realpath validation per entry.
- op_sha256_canonical: NFC-normalizes JSON string leaves so HFS+ (NFD)
  and ext4/APFS (NFC) hash identically; accepts leading blank lines
  before the Markdown marker so IDE auto-prettiers don't reclassify
  generated files as human-curated.
- New ops/flags: protocol-version (skill version decoupled from wire
  protocol), --self-test, stderr traceback on internal errors.
- Hardening: explicit POSIX allow-list, Python 3.10+ guard, /private/var/run
  rejected on macOS, compiled deny-list regex, per-invocation op cap.
- _fd_realpath now uses stdlib fcntl.F_GETPATH on macOS (the prior
  ctypes path failed on real macOS, silently disabling the TOCTOU check).

Tests (tests/test_helper.py, 27 -> 67 tests):
- Allow-list + deny-list enforcement on write-atomic (.git/hooks/, .env,
  node_modules/, escape via intermediate symlink, opt-out flag).
- Lock empty/corrupt/PID-0/negative; two-live-invocation blocking
  (AC 18 now actually exercised, not just manually verified).
- op_walk: symlink-deny-bypass regression (.git via in-workspace
  symlink), per-subtree cap doesn't drop other roots, global cap,
  depth cap, glob dialect.
- NFC/NFD stability, nested-marker preservation, marker-spoof recompute.
- TOCTOU toctouVerified, maxBytes with actual-size, intra-workspace
  symlink open, match-deny ENOENT fallback (allowed + denied), orphan-
  tmp recovery + post-recovery write.
- Generous subprocess timeouts with actionable assertion messages.

CI (.github/workflows/validate.yml):
- New test-aem-agentkit-helper job runs the helper unit suite on every
  PR across Ubuntu + macOS / Python 3.10, 3.11, 3.12. Previously the
  27 tests were documentation only; this makes them a real gate.

Test runner (tests/run-tests.sh):
- Guarded chmod (no working-tree mutation); prints both --version and
  --protocol-version.

Docs:
- SKILL.md: all 13 generation steps numbered; self-validation failures
  categorized (evidence-resolution, module-mismatch, marker-checksum,
  url-scoping, strip-list-survivor, manifest-drift,
  missing-subproject-context); new Threat Model section with in-scope
  and explicitly out-of-scope (prompt-injection via raw bytes, supply-
  chain helper tampering, Windows); allow-list documented as helper-
  enforced; semantic-equivalence wording for role projections.
- 24 templates: replaced 1.0.0-beta literal with {{SKILL_VERSION}}
  token so future version bumps don't require coordinated find/replace.
- AGENTS.module.core, AGENTS.module.ui.apps, AGENTS.subproject got a
  "## After making changes" block instructing the agent to run
  /regen-context. AGENTS.md is read at session start by every spec-
  compliant agent, so the cross-skill index-mutation contract is
  wired where it's actually consumed (rather than touching sibling
  skill SKILL.md files).
- helpers.md: glob dialect explicit (fnmatch, not git-style **);
  protocol-version vs skill-version separation; new write-atomic
  behavior; cleanup-tmp orphan recovery.
- upgrade-and-migration.md: SHA-256 pin table with advisory->hard
  graduation path; templates use {{SKILL_VERSION}}.
- privacy-and-sanitization.md § 2.2: raw bytes via op_open are NOT
  sanitized; orchestrator's responsibility.
- collision-rules.md: dropped 1024-byte _disable_agentkit threshold;
  added case-insensitive FS collision row.
- per-tool-artifacts.md § 7: semantic equivalence (not byte-identical)
  across IDE projections.
- manifest.md: files[].mtime field for v2 incremental drift detection.
- codified-context.md: enterprise-scale cost disclosure.
- README.md: IDE detection signal table synced with SKILL.md.

All 67 tests pass on Python 3.14 (macOS Darwin 24.3).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-07 21:12:35 +05:30
..