Commit Graph

531 Commits

  • fix: address PR #1853 review feedback (force-if-includes, switch, subshell, +refspec)
    Five additional review findings on top of the round-1 tokenizer fix.
    Combined patch surface is small (one push branch, new switch branch,
    exploded subshell handling); all six review issues are now closed.
    
    P1 — --force --force-if-includes still destructive (Greptile, line 217):
      Previous logic treated --force-if-includes as a safety guarantee
      alongside --force-with-lease. Per git-scm.com/docs/git-push,
      --force-if-includes is a no-op WITHOUT --force-with-lease, so a
      combination of --force --force-if-includes is just --force. Push
      branch now treats only --force-with-lease as a lease, and reports
      force when --force / -f is present.
    
    P2 — git switch destructive forms not detected (Greptile, line 234):
      Added a switch branch to isDestructiveGit covering:
        --discard-changes   (explicit discard)
        --force / -f        (ignore conflicts, overwrite)
        -C <branch>         (force-create, overwrites existing branch)
    
    P0 — backtick + $(...) subshell bypass (CodeRabbit, line 64):
      Added explodeSubshells() that promotes `...` and $(...) contents
      to top-level segment separators. Run on both the SQL/dd regex
      input and the per-segment shell tokenizer input. Loops up to 4
      passes to catch a layer of nesting. Without this,
      `echo y | $(rm -rf /tmp)` slipped past the segment splitter
      because the destructive command lived inside a sub-expression.
    
    P0 — +refspec force push (CodeRabbit, line 217):
      `git push origin +main`, `+refs/heads/main:refs/heads/main`, etc.
      force a non-fast-forward update of that specific ref. Push branch
      now also flags any positional arg starting with `+` that matches
      a refspec shape. Excludes bare `+` and numeric-only tokens.
    
    P2 — missing --force --force-if-includes regression test
      (Greptile, line 1202): added.
    
    Tests (+10 on top of the round-1 +10):
      Bypass-now-blocked:
        - git push --force --force-if-includes (force-if-includes is no-op
          without lease — bare force is still in effect)
        - git push origin +main (+refspec bare branch)
        - git push origin +refs/heads/main:refs/heads/main (+refspec full)
        - git switch --discard-changes
        - git switch --force
        - git switch -f (short form)
        - git switch -C (force-create)
        - echo y | `rm -rf /tmp` (backtick subshell)
        - echo y | $(rm -rf /tmp) (dollar-paren subshell)
      Still-allowed:
        - git switch feature (plain)
    
    67/67 in gateguard-fact-force.test.js. 2380/2380 across the full
    suite. yarn lint clean. All seven CI validators pass.
    
    Refs #1843.
  • fix: close gateguard destructive-bash regex bypasses with tokenizer
    Six classes of bypass in scripts/hooks/gateguard-fact-force.js
    DESTRUCTIVE_BASH regex, plus a separate false-positive class.
    Same shape of issue as the block-no-verify holes addressed in
    #1843: a single-regex shell parser can never cover the flag-order
    variations git and rm allow.
    
    Real bypasses observed locally (all ALLOW today, should BLOCK):
    
      git push -f origin main                       (short form of --force)
      git -c core.foo=bar reset --hard              (intervening -c global)
      rm -fr /tmp/junk                              (reverse flag order)
      rm -r -f /tmp/junk                            (split flag form)
      git reset HEAD --hard                         (intervening ref token)
      git clean -fd                                 (combined -f + -d flag)
    
    False positive observed locally (BLOCK today, should ALLOW):
    
      git commit -m "fix: rm -rf race in worker"   (destructive phrase
                                                    inside quoted message)
    
    Behavior fix that comes along: --force-if-includes is now exempted
    alongside --force-with-lease. Both are safety-checked variants;
    the previous regex used a negative lookahead that only spelled out
    --with-lease, so --force-if-includes blocked under the old code
    even though it is the safer-not-harder choice.
    
    Fix shape (mirrors block-no-verify #1843):
    
      - DESTRUCTIVE_SQL_DD regex kept for `drop table`, `delete from`,
        `truncate`, `dd if=` — these are stable keyword phrases. Quoted
        strings are stripped before the regex runs so the phrase is not
        matched inside a commit message body.
      - isDestructiveBash() tokenizes the command into segments at
        unquoted ; | & boundaries, then per segment:
          * isDestructiveRm  — detects `rm` with both r and f set
            across combined or split flag tokens.
          * isDestructiveGit — finds the git subcommand after skipping
            global options (-c key=val, -C path, --git-dir=, etc.),
            then handles reset, checkout --, clean -f*, push --force
            (with --force-with-lease / --force-if-includes exemption),
            commit --amend, and rm -r* preservation.
      - Command tokens go through commandBasename() so /usr/bin/rm,
        rm.exe, and RM all normalize to "rm".
    
    Tests (+10 in tests/hooks/gateguard-fact-force.test.js):
    
      Bypass-now-blocked (7):
        - denies short-form git push -f
        - denies git reset --hard with intervening -c global option
        - denies rm -fr (reverse flag order)
        - denies rm -r -f (split flag form)
        - denies git reset HEAD --hard
        - denies git clean -fd
        - denies destructive command in second chained segment
    
      False-positive-now-allowed (3):
        - allows destructive phrase inside `-m` commit message (rm -rf)
        - allows SQL phrase inside `-m` commit message (drop table)
        - allows --force-if-includes as a safety-checked variant
    
    Local verification:
      yarn lint                                                 clean
      scripts/ci/validate-*  (agents/commands/rules/skills/hooks/
                              install-manifests/no-personal-paths)  pass
      node tests/run-all.js                              2380/2380 pass
    
    Caveat (unrelated): yarn test still fails at check-unicode-safety
    on skills/windows-desktop-e2e/SKILL.md (U+2605) per #1843's
    caveat — independent of this change.
    
    Provenance: discovered during a security pass on ECC after PR
    #1843 (block-no-verify shell-words rewrite) landed. Same class of
    regex-based shell parser issue, same shape of fix.
    
    Refs #1843.
  • docs: gate ECC progress sync readiness
    Make the ECC 2.0 GitHub/Linear/handoff/roadmap progress-sync model part of the local observability readiness gate instead of leaving it as roadmap prose only.
    
    - add `docs/architecture/progress-sync-contract.md` for GitHub, Linear, handoff, roadmap, and work-items sync
    - add a `Tracker Sync` check to `scripts/observability-readiness.js`
    - update observability tests with passing and missing-contract coverage
    - update observability and GA roadmap docs so the local readiness gate is now 18/18 and records #1848 supply-chain hardening evidence
    
    Validation:
    - node tests/scripts/observability-readiness.test.js (9 passed, 0 failed)
    - npm run observability:ready -- --format json (18/18, ready true)
    - npx markdownlint-cli 'docs/architecture/progress-sync-contract.md' 'docs/architecture/observability-readiness.md' 'docs/ECC-2.0-GA-ROADMAP.md'
    - git diff --check
    - node tests/docs/ecc2-release-surface.test.js (18 passed)
    - node tests/run-all.js (2378 passed, 0 failed)
    - GitHub CI for #1849 green across Ubuntu, Windows, and macOS
    
    No release, tag, npm publish, plugin tag, marketplace submission, or announcement was performed.
  • docs: add supply-chain incident response playbook
    Add a repo-level supply-chain incident response playbook for npm/GitHub Actions package-registry incidents, anchored on the May 2026 TanStack compromise and prior Shai-Hulud-style npm incidents.
    
    - add `docs/security/supply-chain-incident-response.md` with exposure checks, immediate response steps, workflow rules, publication rules, and escalation triggers
    - link the playbook from `SECURITY.md`
    - reject `pull_request_target` workflows that restore or save shared dependency caches
    - add a regression test for the new `pull_request_target + actions/cache` guardrail
    
    Validation:
    - node tests/ci/validate-workflow-security.test.js (12 passed, 0 failed)
    - node scripts/ci/validate-workflow-security.js (validated 7 workflow files)
    - npx markdownlint-cli 'SECURITY.md' 'docs/security/supply-chain-incident-response.md'
    - npx markdownlint-cli '**/*.md' --ignore node_modules
    - git diff --check
    - node tests/run-all.js (2377 passed, 0 failed)
    - GitHub CI for #1848 green across Ubuntu, Windows, and macOS
    
    No release, tag, npm publish, plugin tag, marketplace submission, or announcement was performed.
  • ci: require npm audit signature checks
    Require npm registry signature verification wherever workflow npm audit checks run.
    
    - add npm audit signatures to CI Security Scan and maintenance security audit jobs
    - teach the workflow security validator to reject npm audit without signature verification
    - keep the repair and Copilot prompt tests portable across Windows path/case and CRLF frontmatter behavior
    
    Validation:
    - node tests/run-all.js (2376 passed, 0 failed)
    - CI current-head matrix green on #1846
  • feat: add GitHub Copilot prompt support
    Adds GitHub Copilot VS Code instruction and prompt files for ECC workflows, with VS Code prompt frontmatter/settings aligned to current docs and tests covering the surface.
    
    Co-authored-by: Girish Kanjiyani <girish.kanjiyani5040@gmail.com>
    Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
  • fix: close block-no-verify bypass holes
    Backport Jamkris's fix for case-insensitive core.hooksPath overrides and the git commit -tn template-path false positive. Verified locally on current main with 25/25 block-no-verify tests and node tests/run-all.js passing 2369/2369.
  • ci: harden workflow install boundaries
    - run non-test workflow installs with npm ci --ignore-scripts where lifecycle scripts are not needed\n- reject plain npm ci in workflows with write permissions\n- reject actions/cache in id-token: write workflows to reduce OIDC publish cache-poisoning risk
  • feat: salvage Django Celery workflow (#1812)
    Source: maintainer-owned salvage of useful Django reviewer/build-resolver/Celery work from stale PR #1310 by mrigank2seven.
    
    - add django-reviewer and django-build-resolver agents
    
    - add django-celery skill with timezone-aware scheduling example
    
    - update catalog counts to 60 agents / 221 skills and record the May 12 salvage gap pass
    
    Co-authored-by: MRIGANK GUPTA <mrigank2seven@users.noreply.github.com>
  • docs: add data-backed harness adapter scorecard (#1785)
    * docs: add data-backed harness adapter scorecard
    
    * fix: normalize adapter matrix line endings
    
    * test: avoid doubled CRLF simulation
  • feat: add ECC statusline observability hooks
    Salvages the useful statusline/context monitor work from stale PR #1504 while preserving the current continuous-learning hook runner wiring.
    
    Adds the metrics bridge, context monitor, statusline script, shared cost/session bridge utilities, and tests. Fixes the reviewed false loop-detection hash collision for non-file tools, avoids default-session cost inflation, sanitizes statusline task lookup, and records hook payload session IDs in cost-tracker.
  • feat: salvage windows desktop e2e skill
    Reintroduce the Windows desktop E2E testing skill from stale PR #1334 with current manifest wiring, package publish coverage, catalog counts, and sanitized environment-path guidance.