mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-11 02:33:10 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7145ca9dfe | ||
|
|
a8fe098c88 | ||
|
|
faa51fba11 | ||
|
|
4423f10cfb | ||
|
|
3b12fb273f | ||
|
|
4fb80d8861 | ||
|
|
a27831c13e | ||
|
|
b24d762caa | ||
|
|
f94478e524 |
@@ -135,6 +135,42 @@ As of 2026-05-13:
|
|||||||
check-run on the PR head SHA with ready/blocked hosted executor commands
|
check-run on the PR head SHA with ready/blocked hosted executor commands
|
||||||
and next action text, while keeping check-run publication best-effort so
|
and next action text, while keeping check-run publication best-effort so
|
||||||
bundle generation and analysis comments are not blocked.
|
bundle generation and analysis comments are not blocked.
|
||||||
|
- ECC-Tools PR #64 merged as `72020ef94db94840812977ea7ac37e9344036668`
|
||||||
|
and added PR-facing hosted job dispatch controls:
|
||||||
|
`/ecc-tools analyze --job ...` comments now queue hosted jobs against the
|
||||||
|
PR head SHA, execute them through the existing hosted readiness/evidence
|
||||||
|
gates, post artifacts/findings/next actions back to the PR, and scope
|
||||||
|
idempotency keys by job id so hosted jobs do not collide with bundle
|
||||||
|
analysis.
|
||||||
|
- ECC-Tools PR #65 merged as `bacd4adf6a3a629e8d403865456d15f127baaf4e`
|
||||||
|
and added hosted job result history/check-run summaries:
|
||||||
|
queued hosted jobs now cache both the latest result and immutable run records
|
||||||
|
for completed or blocked runs, then publish a non-blocking per-job check-run
|
||||||
|
on the PR head SHA with artifacts, findings, readiness blockers, and next
|
||||||
|
actions.
|
||||||
|
- ECC-Tools PR #66 merged as `4e1db48252d068ea5dcf4308b0bc11b0dfe0c9ce`
|
||||||
|
and added a read-only hosted status command:
|
||||||
|
`/ecc-tools analyze --job status` now reads the #65 latest-result cache for
|
||||||
|
the current PR head and posts a compact completed/blocked/not-run table with
|
||||||
|
the next hosted job command, without queueing work or billing usage.
|
||||||
|
- ECC-Tools PR #67 merged as `f20e6bec2b0bf49e4cc36e08b7285c795973b73d`
|
||||||
|
and made the hosted depth-plan check-run status-aware:
|
||||||
|
queued PR analysis now reads the #65/#66 latest-result cache when publishing
|
||||||
|
`ECC Tools / Hosted Depth Plan`, includes the latest hosted run status in
|
||||||
|
the plan table, and recommends the next unrun ready job before reruns.
|
||||||
|
- ECC-Tools PR #68 merged as `2cde524b5ef8f34ab7bb1af973248fe4be4359f8`
|
||||||
|
and added deterministic hosted promotion readiness:
|
||||||
|
opened/synchronized PRs now publish a non-blocking
|
||||||
|
`ECC Tools / Hosted Promotion Readiness` check-run that compares changed
|
||||||
|
files against the checked-in evaluator/RAG corpus, warns on missing
|
||||||
|
hosted-job promotion evidence, and can be disabled with
|
||||||
|
`PR_HOSTED_PROMOTION_READINESS_CHECK_MODE=off`.
|
||||||
|
- ECC-Tools PR #69 merged as `d0112dac7cef807ae27def41f057682ef0772cce`
|
||||||
|
and extended hosted promotion readiness with deterministic output scoring:
|
||||||
|
the check now reads cached completed hosted job results for the current PR
|
||||||
|
head, scores their artifacts and findings against evaluator/RAG corpus
|
||||||
|
expectations, and treats matching hosted artifacts as promotion evidence
|
||||||
|
before reporting a gap.
|
||||||
- Handoff `ecc-supply-chain-audit-20260513-0645.md` under
|
- Handoff `ecc-supply-chain-audit-20260513-0645.md` under
|
||||||
`~/.cluster-swarm/handoffs/`
|
`~/.cluster-swarm/handoffs/`
|
||||||
records the May 13 supply-chain sweep: no active lockfile/manifest hit for
|
records the May 13 supply-chain sweep: no active lockfile/manifest hit for
|
||||||
@@ -356,6 +392,28 @@ As of 2026-05-13:
|
|||||||
- ECC-Tools PR #63 publishes the hosted depth-plan check-run after queued PR
|
- ECC-Tools PR #63 publishes the hosted depth-plan check-run after queued PR
|
||||||
analysis completes, making the six hosted executor commands visible on the
|
analysis completes, making the six hosted executor commands visible on the
|
||||||
PR head SHA without turning the check into a merge blocker.
|
PR head SHA without turning the check into a merge blocker.
|
||||||
|
- ECC-Tools PR #64 wires those commands into the queue: maintainers can comment
|
||||||
|
`/ecc-tools analyze --job ci-diagnostics`, `security-evidence`,
|
||||||
|
`harness-compatibility`, `reference-set-evaluation`, `ai-routing-cost`, or
|
||||||
|
`team-backlog` on a PR and receive hosted job results in a PR comment.
|
||||||
|
- ECC-Tools PR #65 persists completed and blocked hosted job results to the
|
||||||
|
analysis cache for 30 days and publishes non-blocking `ECC Tools / Hosted
|
||||||
|
Job: ...` check-runs so maintainers can scan hosted outcomes from the PR
|
||||||
|
checks surface instead of rereading older comments.
|
||||||
|
- ECC-Tools PR #66 exposes the cached results from PR comments with
|
||||||
|
`/ecc-tools analyze --job status`, summarizing completed, blocked, and
|
||||||
|
not-yet-run hosted jobs for the PR head and recommending the next hosted job
|
||||||
|
command.
|
||||||
|
- ECC-Tools PR #67 feeds those cached results back into the hosted depth-plan
|
||||||
|
check-run so queued analysis recommends the next unrun ready hosted job from
|
||||||
|
cache state instead of repeating the static readiness order.
|
||||||
|
- ECC-Tools PR #68 adds the first evaluator-backed hosted promotion gate:
|
||||||
|
opened/synchronized PRs get a non-blocking Hosted Promotion Readiness
|
||||||
|
check-run that turns the evaluator/RAG corpus into warnings when changed
|
||||||
|
files match fixture scenarios without their expected evidence artifacts.
|
||||||
|
- ECC-Tools PR #69 extends that gate to score cached completed hosted job
|
||||||
|
outputs for the current PR head, so hosted artifacts can satisfy corpus
|
||||||
|
evidence expectations before the check reports a promotion gap.
|
||||||
- ECC PR #1803 landed the contributor Quarkus handling branch after maintainer
|
- ECC PR #1803 landed the contributor Quarkus handling branch after maintainer
|
||||||
cleanup, current-`main` alignment, full local validation, and preservation of
|
cleanup, current-`main` alignment, full local validation, and preservation of
|
||||||
the author's removal of incomplete ja-JP and zh-CN Quarkus translations.
|
the author's removal of incomplete ja-JP and zh-CN Quarkus translations.
|
||||||
@@ -409,10 +467,10 @@ is not complete unless the evidence column exists and has been freshly verified.
|
|||||||
| Claude and Codex plugin publication | Contact/submission path with required artifacts and status | Publication readiness, naming matrix, and May 12 dry-run evidence document plugin validation, clean-checkout Claude tag/install smoke, and Codex marketplace CLI shape | Needs explicit approval for real tag/push and marketplace submission |
|
| Claude and Codex plugin publication | Contact/submission path with required artifacts and status | Publication readiness, naming matrix, and May 12 dry-run evidence document plugin validation, clean-checkout Claude tag/install smoke, and Codex marketplace CLI shape | Needs explicit approval for real tag/push and marketplace submission |
|
||||||
| Articles, tweets, and announcements | X thread, LinkedIn copy, GitHub release copy, push checklist | Draft launch collateral exists under rc.1 release docs | Needs URL-backed refresh |
|
| Articles, tweets, and announcements | X thread, LinkedIn copy, GitHub release copy, push checklist | Draft launch collateral exists under rc.1 release docs | Needs URL-backed refresh |
|
||||||
| AgentShield enterprise iteration | Policy gates, SARIF, packs, provenance, corpus, HTML reports, exception lifecycle audit, baseline drift Action/CLI surfaces, evidence-pack redaction, harness adapter registry, enterprise research roadmap, supply-chain hardened release path, CI-safe baseline fingerprints, corpus accuracy recommendations, remediation workflow phases, env proxy hijack corpus coverage | PRs #53, #55-#64, #67-#69, and #78-#82 landed with test evidence; native PDF export deferred in favor of self-contained HTML plus print-to-PDF until explicit enterprise demand appears; `docs/architecture/agentshield-enterprise-research-roadmap.md` now has baseline drift, evidence-pack bundle, redaction, adapter-registry, supply-chain hardening, hashed baseline fingerprints, corpus accuracy recommendation, remediation workflow, and env proxy hijack corpus slices landed | Next hosted evidence-pack workflow depth |
|
| AgentShield enterprise iteration | Policy gates, SARIF, packs, provenance, corpus, HTML reports, exception lifecycle audit, baseline drift Action/CLI surfaces, evidence-pack redaction, harness adapter registry, enterprise research roadmap, supply-chain hardened release path, CI-safe baseline fingerprints, corpus accuracy recommendations, remediation workflow phases, env proxy hijack corpus coverage | PRs #53, #55-#64, #67-#69, and #78-#82 landed with test evidence; native PDF export deferred in favor of self-contained HTML plus print-to-PDF until explicit enterprise demand appears; `docs/architecture/agentshield-enterprise-research-roadmap.md` now has baseline drift, evidence-pack bundle, redaction, adapter-registry, supply-chain hardening, hashed baseline fingerprints, corpus accuracy recommendation, remediation workflow, and env proxy hijack corpus slices landed | Next hosted evidence-pack workflow depth |
|
||||||
| ECC Tools next-level app | Billing audit, PR checks, deep analyzer, sync backlog, evaluator/RAG corpus, analysis-depth readiness, hosted execution planning, hosted CI diagnostics, hosted security evidence review, hosted harness compatibility audit, hosted reference-set evaluation, hosted AI routing/cost review, hosted team backlog routing, hosted depth-plan check-run | PRs #26-#43 plus #53-#63 landed with test evidence, including AgentShield evidence-pack gap routing, canonical bundle recognition, supply-chain signature gates, PR draft follow-up Linear tracking, evidence-backed/deep-ready repository classification, the `/api/analysis/depth-plan` hosted job plan, `/api/analysis/jobs/ci-diagnostics`, `/api/analysis/jobs/security-evidence-review`, `/api/analysis/jobs/harness-compatibility-audit`, `/api/analysis/jobs/reference-set-evaluation`, `/api/analysis/jobs/ai-routing-cost-review`, `/api/analysis/jobs/team-backlog-routing`, and the `ECC Tools / Hosted Depth Plan` check-run | Hosted operator visibility complete; next work is hosted-job dispatch execution controls |
|
| ECC Tools next-level app | Billing audit, PR checks, deep analyzer, sync backlog, evaluator/RAG corpus, analysis-depth readiness, hosted execution planning, hosted CI diagnostics, hosted security evidence review, hosted harness compatibility audit, hosted reference-set evaluation, hosted AI routing/cost review, hosted team backlog routing, hosted depth-plan check-run, PR-comment hosted job dispatch, hosted job result history/check-runs, hosted result status command, status-aware depth-plan recommendations, hosted promotion readiness, hosted promotion output scoring | PRs #26-#43 plus #53-#69 landed with test evidence, including AgentShield evidence-pack gap routing, canonical bundle recognition, supply-chain signature gates, PR draft follow-up Linear tracking, evidence-backed/deep-ready repository classification, the `/api/analysis/depth-plan` hosted job plan, `/api/analysis/jobs/ci-diagnostics`, `/api/analysis/jobs/security-evidence-review`, `/api/analysis/jobs/harness-compatibility-audit`, `/api/analysis/jobs/reference-set-evaluation`, `/api/analysis/jobs/ai-routing-cost-review`, `/api/analysis/jobs/team-backlog-routing`, the `ECC Tools / Hosted Depth Plan` check-run, `/ecc-tools analyze --job ...` PR-comment dispatch, non-blocking per-hosted-job result check-runs backed by 30-day result cache records, `/ecc-tools analyze --job status` cache lookup, cache-aware next-job recommendations in the depth-plan check-run, the `ECC Tools / Hosted Promotion Readiness` corpus-backed PR check-run, and deterministic hosted-output scoring against cached completed job artifacts/findings | Next work is retrieval/model-backed hosted promotion after deterministic output scoring |
|
||||||
| GitGuardian/Dependabot/CodeRabbit-style checks | Non-blocking taxonomy, deterministic follow-up checks, and local supply-chain gates | ECC-Tools risk taxonomy check plus follow-up signals landed, including Skill Quality, Deep Analyzer Evidence, Analyzer Corpus Evidence, RAG/Evaluator Evidence, PR Review/Salvage Evidence, and AgentShield evidence-pack evidence; #1846 added npm registry signature gates; #1848 added the supply-chain incident-response playbook and `pull_request_target` cache-poisoning validator guard; #1851 added the privileged checkout credential-persistence guard; AgentShield #78, JARVIS #13, and ECC-Tools #53 applied the same hardening outside trunk | Current supply-chain gate complete; deeper hosted review features remain future |
|
| GitGuardian/Dependabot/CodeRabbit-style checks | Non-blocking taxonomy, deterministic follow-up checks, and local supply-chain gates | ECC-Tools risk taxonomy check plus follow-up signals landed, including Skill Quality, Deep Analyzer Evidence, Analyzer Corpus Evidence, RAG/Evaluator Evidence, PR Review/Salvage Evidence, and AgentShield evidence-pack evidence; #1846 added npm registry signature gates; #1848 added the supply-chain incident-response playbook and `pull_request_target` cache-poisoning validator guard; #1851 added the privileged checkout credential-persistence guard; AgentShield #78, JARVIS #13, and ECC-Tools #53 applied the same hardening outside trunk | Current supply-chain gate complete; deeper hosted review features remain future |
|
||||||
| Harness-agnostic learning system | Audit, adapter matrix, observability, traces, promotion loop | Audit/adapters/observability gates plus `docs/architecture/evaluator-rag-prototype.md`, `examples/evaluator-rag-prototype/`, and ECC-Tools PR #40 define read-only stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison scenarios with trace, report, playbook, verifier, and predictive-check artifacts | Local corpus complete; hosted integration remains future |
|
| Harness-agnostic learning system | Audit, adapter matrix, observability, traces, promotion loop | Audit/adapters/observability gates plus `docs/architecture/evaluator-rag-prototype.md`, `examples/evaluator-rag-prototype/`, and ECC-Tools PR #40 define read-only stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison scenarios with trace, report, playbook, verifier, and predictive-check artifacts; ECC-Tools PRs #68/#69 now turn that corpus into a deterministic PR check-run gate with cached hosted-output scoring | Deterministic hosted PR check and cached output scoring integrated; hosted retrieval remains future |
|
||||||
| Linear roadmap is detailed | Linear project status plus repo mirror | Repo mirror exists; issue creation was retried on 2026-05-12 and remains blocked by the workspace free issue limit; this May 13 sync adds ECC #1860, AgentShield #78-#82, JARVIS #13, ECC-Tools #53-#63, resolved queue/discussion counts, and Linear project status updates through ECC-Tools #63 | Needs recurring status updates after each merge batch |
|
| Linear roadmap is detailed | Linear project status plus repo mirror | Repo mirror exists; issue creation was retried on 2026-05-12 and remains blocked by the workspace free issue limit; this May 13 sync adds ECC #1860, AgentShield #78-#82, JARVIS #13, ECC-Tools #53-#69, resolved queue/discussion counts, and Linear project status updates through ECC-Tools #69 | Needs recurring status updates after each merge batch |
|
||||||
| Flow separation and progress tracking | Flow lanes with owner artifacts and update cadence | This roadmap defines lanes below and `docs/architecture/progress-sync-contract.md` makes GitHub/Linear/handoff/roadmap sync part of the readiness gate | Active |
|
| Flow separation and progress tracking | Flow lanes with owner artifacts and update cadence | This roadmap defines lanes below and `docs/architecture/progress-sync-contract.md` makes GitHub/Linear/handoff/roadmap sync part of the readiness gate | Active |
|
||||||
| Realtime Linear sync | Project updates while issue limit is blocked; issues later | ECC-Tools #39 implements opt-in Linear API sync for deferred follow-up backlog items, and ECC-Tools #54 adds copy-ready PR drafts to that backlog when draft PR shells are not opened; `docs/architecture/progress-sync-contract.md` defines the local file-backed realtime boundary while issue capacity is blocked | Needs workspace capacity/config rollout |
|
| Realtime Linear sync | Project updates while issue limit is blocked; issues later | ECC-Tools #39 implements opt-in Linear API sync for deferred follow-up backlog items, and ECC-Tools #54 adds copy-ready PR drafts to that backlog when draft PR shells are not opened; `docs/architecture/progress-sync-contract.md` defines the local file-backed realtime boundary while issue capacity is blocked | Needs workspace capacity/config rollout |
|
||||||
| Observability for self-use | Local readiness gate, traces, status snapshots, HUD/status contract, risk ledger, progress-sync contract | `npm run observability:ready` reports 21/21 | Complete for local gate |
|
| Observability for self-use | Local readiness gate, traces, status snapshots, HUD/status contract, risk ledger, progress-sync contract | `npm run observability:ready` reports 21/21 | Complete for local gate |
|
||||||
@@ -431,9 +489,9 @@ repo evidence and merge commits.
|
|||||||
| Queue hygiene and salvage | GitHub PR/issue state, salvage ledger | Append ledger entries for any future stale closures | Every cleanup batch |
|
| Queue hygiene and salvage | GitHub PR/issue state, salvage ledger | Append ledger entries for any future stale closures | Every cleanup batch |
|
||||||
| Release and publication | rc.1 release docs, publication readiness doc | Naming matrix and plugin submission/contact checklist | Before any tag |
|
| Release and publication | rc.1 release docs, publication readiness doc | Naming matrix and plugin submission/contact checklist | Before any tag |
|
||||||
| Harness OS core | Audit, adapter matrix, observability docs, `ecc2/` | HUD/session-control acceptance spec | Weekly until GA |
|
| Harness OS core | Audit, adapter matrix, observability docs, `ecc2/` | HUD/session-control acceptance spec | Weekly until GA |
|
||||||
| Evaluation and RAG | Reference-set validation, harness audit, traces, ECC-Tools corpus | Read-only evaluator/RAG prototype plus stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison fixtures | Hosted retrieval/check-run automation plan |
|
| Evaluation and RAG | Reference-set validation, harness audit, traces, ECC-Tools corpus | Read-only evaluator/RAG prototype plus stale-salvage, billing-readiness, CI-failure-diagnosis, harness-config-quality, AgentShield policy-exception, skill-quality evidence, deep-analyzer evidence, and RAG/evaluator comparison fixtures; ECC-Tools #68 publishes the corpus as a hosted promotion readiness check-run, and #69 scores cached hosted job outputs against the same corpus | Hosted retrieval/model-backed promotion plan |
|
||||||
| AgentShield enterprise | AgentShield PR evidence and roadmap notes | Remediation workflow depth or corpus expansion follow-up | Next implementation batch |
|
| AgentShield enterprise | AgentShield PR evidence and roadmap notes | Remediation workflow depth or corpus expansion follow-up | Next implementation batch |
|
||||||
| ECC Tools app | ECC-Tools PR evidence, billing audit, risk taxonomy, evaluator/RAG corpus | ECC-Tools #53 published the supply-chain workflow hardening branch, #54 tracks copy-ready PR drafts in the Linear/project backlog, #55 classifies analysis-depth readiness, #56 exposes the hosted execution plan, #57 executes the first hosted CI diagnostics job, #58 executes the hosted security evidence review job, #59 executes the hosted harness compatibility audit, #60 executes the hosted reference-set evaluation, #61 executes the hosted AI routing/cost review, #62 executes hosted team backlog routing, and #63 publishes the hosted depth-plan check-run; next work is hosted-job dispatch execution controls | Next implementation batch |
|
| ECC Tools app | ECC-Tools PR evidence, billing audit, risk taxonomy, evaluator/RAG corpus | ECC-Tools #53 published the supply-chain workflow hardening branch, #54 tracks copy-ready PR drafts in the Linear/project backlog, #55 classifies analysis-depth readiness, #56 exposes the hosted execution plan, #57 executes the first hosted CI diagnostics job, #58 executes the hosted security evidence review job, #59 executes the hosted harness compatibility audit, #60 executes the hosted reference-set evaluation, #61 executes the hosted AI routing/cost review, #62 executes hosted team backlog routing, #63 publishes the hosted depth-plan check-run, #64 dispatches hosted jobs from PR comments, #65 persists hosted result history/check-runs, #66 exposes hosted job status from PR comments, #67 makes depth-plan recommendations cache-aware, #68 publishes hosted promotion readiness from the evaluator/RAG corpus, and #69 scores cached hosted job outputs against that corpus; next work is retrieval/model-backed hosted promotion | Next implementation batch |
|
||||||
| Linear progress | Linear project status updates, `docs/architecture/progress-sync-contract.md`, and this mirror | Status update with queue/evidence/missing gates | Every significant merge batch |
|
| Linear progress | Linear project status updates, `docs/architecture/progress-sync-contract.md`, and this mirror | Status update with queue/evidence/missing gates | Every significant merge batch |
|
||||||
|
|
||||||
The project status update should always include:
|
The project status update should always include:
|
||||||
@@ -650,10 +708,9 @@ Acceptance:
|
|||||||
PR #82 expanded corpus coverage for env proxy hijacks and out-of-band
|
PR #82 expanded corpus coverage for env proxy hijacks and out-of-band
|
||||||
exfiltration; and ECC-Tools PRs #42/#43 now route and recognize evidence
|
exfiltration; and ECC-Tools PRs #42/#43 now route and recognize evidence
|
||||||
packs. The next slice is hosted evidence-pack workflow depth.
|
packs. The next slice is hosted evidence-pack workflow depth.
|
||||||
2. Build hosted-job dispatch execution controls on top of the #63 hosted
|
2. Plan retrieval/model-backed hosted promotion on top of the #69 deterministic
|
||||||
depth-plan check-run so maintainers can queue the selected CI, security,
|
hosted output scoring contract, keeping vector/model judgment behind fixture
|
||||||
harness, reference-set, AI-routing, or team-backlog job from the PR-facing
|
evaluation until the retrieval contract is stable.
|
||||||
operator surface instead of manually calling the internal endpoints.
|
|
||||||
3. Enable/configure the merged Linear backlog sync path after workspace issue
|
3. Enable/configure the merged Linear backlog sync path after workspace issue
|
||||||
capacity clears or the Linear workspace is upgraded, then verify PR-draft
|
capacity clears or the Linear workspace is upgraded, then verify PR-draft
|
||||||
salvage items land in the expected project.
|
salvage items land in the expected project.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ paths:
|
|||||||
Configure project-local hooks to prefer binstubs and checked-in tooling:
|
Configure project-local hooks to prefer binstubs and checked-in tooling:
|
||||||
|
|
||||||
- **RuboCop**: run `bundle exec rubocop -A <file>` or the project's safer formatter command after Ruby edits.
|
- **RuboCop**: run `bundle exec rubocop -A <file>` or the project's safer formatter command after Ruby edits.
|
||||||
- **Brakeman**: run `bundle exec brakeman --no-progress` after security-sensitive Rails changes.
|
- **Brakeman**: run `bundle exec brakeman --no-pager` after security-sensitive Rails changes.
|
||||||
- **Tests**: run the narrowest matching `bin/rails test ...` or `bundle exec rspec ...` command for touched files.
|
- **Tests**: run the narrowest matching `bin/rails test ...` or `bundle exec rspec ...` command for touched files.
|
||||||
- **Bundler audit**: run `bundle exec bundle-audit check --update` when `Gemfile` or `Gemfile.lock` changes and the project has bundler-audit installed.
|
- **Bundler audit**: run `bundle exec bundle-audit check --update` when `Gemfile` or `Gemfile.lock` changes and the project has bundler-audit installed.
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ Configure project-local hooks to prefer binstubs and checked-in tooling:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
bundle exec rubocop
|
bundle exec rubocop
|
||||||
bundle exec brakeman --no-progress
|
bundle exec brakeman --no-pager
|
||||||
bin/rails test
|
bin/rails test
|
||||||
bundle exec rspec
|
bundle exec rspec
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ paths:
|
|||||||
- Run dependency checks when the lockfile changes:
|
- Run dependency checks when the lockfile changes:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bundle exec bundle-audit check --update
|
bundle audit check --update
|
||||||
bundle exec brakeman --no-progress
|
bundle exec brakeman --no-pager
|
||||||
```
|
```
|
||||||
|
|
||||||
- Review new gems for maintainer activity, native extension risk, transitive dependencies, and whether the same behavior can be implemented with Rails core.
|
- Review new gems for maintainer activity, native extension risk, transitive dependencies, and whether the same behavior can be implemented with Rails core.
|
||||||
|
|||||||
@@ -7,12 +7,13 @@
|
|||||||
* the actual code. This hook steers the agent back to fixing the source.
|
* the actual code. This hook steers the agent back to fixing the source.
|
||||||
*
|
*
|
||||||
* Exit codes:
|
* Exit codes:
|
||||||
* 0 = allow (not a config file)
|
* 0 = allow (not a config file, or first-time creation of one)
|
||||||
* 2 = block (config file modification attempted)
|
* 2 = block (existing config file modification attempted)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const MAX_STDIN = 1024 * 1024;
|
const MAX_STDIN = 1024 * 1024;
|
||||||
@@ -58,7 +59,7 @@ const PROTECTED_FILES = new Set([
|
|||||||
'.stylelintrc.yml',
|
'.stylelintrc.yml',
|
||||||
'.markdownlint.json',
|
'.markdownlint.json',
|
||||||
'.markdownlint.yaml',
|
'.markdownlint.yaml',
|
||||||
'.markdownlintrc',
|
'.markdownlintrc'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function parseInput(inputOrRaw) {
|
function parseInput(inputOrRaw) {
|
||||||
@@ -94,13 +95,41 @@ function run(inputOrRaw, options = {}) {
|
|||||||
|
|
||||||
const basename = path.basename(filePath);
|
const basename = path.basename(filePath);
|
||||||
if (PROTECTED_FILES.has(basename)) {
|
if (PROTECTED_FILES.has(basename)) {
|
||||||
|
// Allow first-time creation — there's no existing config to weaken.
|
||||||
|
// The hook's purpose is blocking modifications; writing a brand-new
|
||||||
|
// config file in a project that has none is a legitimate bootstrap
|
||||||
|
// path (e.g. scaffolding ESLint into a fresh repo).
|
||||||
|
//
|
||||||
|
// Fail closed on any stat error other than ENOENT. Use lstatSync so a
|
||||||
|
// symlink at the protected path is treated as present even if its target
|
||||||
|
// is missing — a dangling symlink at e.g. .eslintrc.js still represents
|
||||||
|
// an existing config entry that an agent should not silently replace.
|
||||||
|
// fs.existsSync would swallow EACCES/EPERM as false; lstatSync exposes
|
||||||
|
// the error code so we can treat only genuine "path not found" (ENOENT)
|
||||||
|
// as absent.
|
||||||
|
let exists = true;
|
||||||
|
try {
|
||||||
|
fs.lstatSync(filePath);
|
||||||
|
// lstat succeeded — something (file, dir, or symlink) exists here.
|
||||||
|
} catch (err) {
|
||||||
|
if (err && err.code === 'ENOENT') {
|
||||||
|
exists = false;
|
||||||
|
}
|
||||||
|
// Any other error (EACCES, EPERM, ELOOP, etc.) leaves exists=true
|
||||||
|
// so the guard is never silently weakened.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exists) {
|
||||||
|
return { exitCode: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
exitCode: 2,
|
exitCode: 2,
|
||||||
stderr:
|
stderr:
|
||||||
`BLOCKED: Modifying ${basename} is not allowed. ` +
|
`BLOCKED: Modifying ${basename} is not allowed. ` +
|
||||||
'Fix the source code to satisfy linter/formatter rules instead of ' +
|
'Fix the source code to satisfy linter/formatter rules instead of ' +
|
||||||
'weakening the config. If this is a legitimate config change, ' +
|
'weakening the config. If this is a legitimate config change, ' +
|
||||||
'disable the config-protection hook temporarily.',
|
'disable the config-protection hook temporarily.'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +154,7 @@ process.stdin.on('data', chunk => {
|
|||||||
process.stdin.on('end', () => {
|
process.stdin.on('end', () => {
|
||||||
const result = run(raw, {
|
const result = run(raw, {
|
||||||
truncated,
|
truncated,
|
||||||
maxStdin: Number(process.env.ECC_HOOK_INPUT_MAX_BYTES) || MAX_STDIN,
|
maxStdin: Number(process.env.ECC_HOOK_INPUT_MAX_BYTES) || MAX_STDIN
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.stderr) {
|
if (result.stderr) {
|
||||||
|
|||||||
@@ -130,12 +130,12 @@ test('candidate playbook preserves stale-salvage operating rules', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('roadmap points to the evaluator RAG prototype and keeps hosted integration open', () => {
|
test('roadmap points to the evaluator RAG prototype and hosted PR check', () => {
|
||||||
const roadmap = read('docs/ECC-2.0-GA-ROADMAP.md');
|
const roadmap = read('docs/ECC-2.0-GA-ROADMAP.md');
|
||||||
|
|
||||||
assert.ok(roadmap.includes('docs/architecture/evaluator-rag-prototype.md'));
|
assert.ok(roadmap.includes('docs/architecture/evaluator-rag-prototype.md'));
|
||||||
assert.ok(roadmap.includes('examples/evaluator-rag-prototype/'));
|
assert.ok(roadmap.includes('examples/evaluator-rag-prototype/'));
|
||||||
assert.ok(roadmap.includes('Local corpus complete; hosted integration remains future'));
|
assert.ok(roadmap.includes('Deterministic hosted PR check and cached output scoring integrated; hosted retrieval remains future'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('billing readiness scenario rejects launch copy overclaims', () => {
|
test('billing readiness scenario rejects launch copy overclaims', () => {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { spawnSync } = require('child_process');
|
const { spawnSync } = require('child_process');
|
||||||
|
|
||||||
@@ -70,85 +71,249 @@ function runTests() {
|
|||||||
let passed = 0;
|
let passed = 0;
|
||||||
let failed = 0;
|
let failed = 0;
|
||||||
|
|
||||||
if (test('blocks protected config file edits through run-with-flags', () => {
|
if (
|
||||||
const input = {
|
test('blocks protected config file edits through run-with-flags', () => {
|
||||||
tool_name: 'Write',
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
|
||||||
tool_input: {
|
try {
|
||||||
file_path: '.eslintrc.js',
|
const absPath = path.join(tmpDir, '.eslintrc.js');
|
||||||
content: 'module.exports = {};'
|
fs.writeFileSync(absPath, 'module.exports = {};');
|
||||||
|
|
||||||
|
const input = {
|
||||||
|
tool_name: 'Write',
|
||||||
|
tool_input: {
|
||||||
|
file_path: absPath,
|
||||||
|
content: 'module.exports = {};'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = runHook(input);
|
||||||
|
assert.strictEqual(result.code, 2, 'Expected protected config edit to be blocked');
|
||||||
|
assert.strictEqual(result.stdout, '', 'Blocked hook should not echo raw input');
|
||||||
|
assert.ok(result.stderr.includes('BLOCKED: Modifying .eslintrc.js is not allowed.'), `Expected block message, got: ${result.stderr}`);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||||
|
} catch {
|
||||||
|
// best-effort cleanup
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
|
||||||
const result = runHook(input);
|
if (
|
||||||
assert.strictEqual(result.code, 2, 'Expected protected config edit to be blocked');
|
test('passes through safe file edits unchanged', () => {
|
||||||
assert.strictEqual(result.stdout, '', 'Blocked hook should not echo raw input');
|
const input = {
|
||||||
assert.ok(result.stderr.includes('BLOCKED: Modifying .eslintrc.js is not allowed.'), `Expected block message, got: ${result.stderr}`);
|
tool_name: 'Write',
|
||||||
})) passed++; else failed++;
|
tool_input: {
|
||||||
|
file_path: 'src/index.js',
|
||||||
|
content: 'console.log("ok");'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (test('passes through safe file edits unchanged', () => {
|
const rawInput = JSON.stringify(input);
|
||||||
const input = {
|
const result = runHook(input);
|
||||||
tool_name: 'Write',
|
assert.strictEqual(result.code, 0, 'Expected safe file edit to pass');
|
||||||
tool_input: {
|
assert.strictEqual(result.stdout, rawInput, 'Expected exact raw JSON passthrough');
|
||||||
file_path: 'src/index.js',
|
assert.strictEqual(result.stderr, '', 'Expected no stderr for safe edits');
|
||||||
content: 'console.log("ok");'
|
})
|
||||||
}
|
)
|
||||||
};
|
passed++;
|
||||||
|
else failed++;
|
||||||
const rawInput = JSON.stringify(input);
|
|
||||||
const result = runHook(input);
|
|
||||||
assert.strictEqual(result.code, 0, 'Expected safe file edit to pass');
|
|
||||||
assert.strictEqual(result.stdout, rawInput, 'Expected exact raw JSON passthrough');
|
|
||||||
assert.strictEqual(result.stderr, '', 'Expected no stderr for safe edits');
|
|
||||||
})) passed++; else failed++;
|
|
||||||
|
|
||||||
if (test('blocks truncated protected config payloads instead of failing open', () => {
|
|
||||||
const rawInput = JSON.stringify({
|
|
||||||
tool_name: 'Write',
|
|
||||||
tool_input: {
|
|
||||||
file_path: '.eslintrc.js',
|
|
||||||
content: 'x'.repeat(1024 * 1024 + 2048)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = runHook(rawInput);
|
|
||||||
assert.strictEqual(result.code, 2, 'Expected truncated protected payload to be blocked');
|
|
||||||
assert.strictEqual(result.stdout, '', 'Blocked truncated payload should not echo raw input');
|
|
||||||
assert.ok(result.stderr.includes('Hook input exceeded 1048576 bytes'), `Expected size warning, got: ${result.stderr}`);
|
|
||||||
assert.ok(result.stderr.includes('truncated payload'), `Expected truncated payload warning, got: ${result.stderr}`);
|
|
||||||
})) passed++; else failed++;
|
|
||||||
|
|
||||||
if (test('legacy hooks do not echo raw input when they fail without stdout', () => {
|
|
||||||
const pluginRoot = path.join(__dirname, '..', `tmp-runner-plugin-${Date.now()}`);
|
|
||||||
const scriptDir = path.join(pluginRoot, 'scripts', 'hooks');
|
|
||||||
const scriptPath = path.join(scriptDir, 'legacy-block.js');
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs.mkdirSync(scriptDir, { recursive: true });
|
|
||||||
fs.writeFileSync(
|
|
||||||
scriptPath,
|
|
||||||
'#!/usr/bin/env node\nprocess.stderr.write("blocked by legacy hook\\n");\nprocess.exit(2);\n'
|
|
||||||
);
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
test('blocks truncated protected config payloads instead of failing open', () => {
|
||||||
const rawInput = JSON.stringify({
|
const rawInput = JSON.stringify({
|
||||||
tool_name: 'Write',
|
tool_name: 'Write',
|
||||||
tool_input: {
|
tool_input: {
|
||||||
file_path: '.eslintrc.js',
|
file_path: '.eslintrc.js',
|
||||||
content: 'module.exports = {};'
|
content: 'x'.repeat(1024 * 1024 + 2048)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = runCustomHook(pluginRoot, 'pre:legacy-block', 'scripts/hooks/legacy-block.js', rawInput);
|
const result = runHook(rawInput);
|
||||||
assert.strictEqual(result.code, 2, 'Expected failing legacy hook exit code to propagate');
|
assert.strictEqual(result.code, 2, 'Expected truncated protected payload to be blocked');
|
||||||
assert.strictEqual(result.stdout, '', 'Expected failing legacy hook to avoid raw passthrough');
|
assert.strictEqual(result.stdout, '', 'Blocked truncated payload should not echo raw input');
|
||||||
assert.ok(result.stderr.includes('blocked by legacy hook'), `Expected legacy hook stderr, got: ${result.stderr}`);
|
assert.ok(result.stderr.includes('Hook input exceeded 1048576 bytes'), `Expected size warning, got: ${result.stderr}`);
|
||||||
} finally {
|
assert.ok(result.stderr.includes('truncated payload'), `Expected truncated payload warning, got: ${result.stderr}`);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
|
||||||
|
if (
|
||||||
|
test('allows first-time creation of a protected config file', () => {
|
||||||
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
|
||||||
try {
|
try {
|
||||||
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
const absPath = path.join(tmpDir, 'eslint.config.mjs');
|
||||||
} catch {
|
const input = {
|
||||||
// best-effort cleanup
|
tool_name: 'Write',
|
||||||
|
tool_input: {
|
||||||
|
file_path: absPath,
|
||||||
|
content: 'export default [];'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawInput = JSON.stringify(input);
|
||||||
|
const result = runHook(input);
|
||||||
|
assert.strictEqual(result.code, 0, `Expected exit 0 for first-time creation, got ${result.code}; stderr: ${result.stderr}`);
|
||||||
|
assert.strictEqual(result.stdout, rawInput, 'Expected raw passthrough when creation is allowed');
|
||||||
|
assert.strictEqual(result.stderr, '', `Expected no stderr for first-time creation, got: ${result.stderr}`);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||||
|
} catch {
|
||||||
|
// best-effort cleanup
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})) passed++; else failed++;
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
|
||||||
|
if (
|
||||||
|
test('allows first-time creation when the parent directory does not exist yet', () => {
|
||||||
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
|
||||||
|
try {
|
||||||
|
// Path under a non-existent subdirectory — statSync returns ENOENT
|
||||||
|
// on the final segment, which should be treated as "does not exist"
|
||||||
|
// and allow the write. (Agent or CLI is expected to create parents
|
||||||
|
// during the Write itself; this hook does not need to.)
|
||||||
|
const absPath = path.join(tmpDir, 'no-such-parent', '.prettierrc');
|
||||||
|
const input = {
|
||||||
|
tool_name: 'Write',
|
||||||
|
tool_input: {
|
||||||
|
file_path: absPath,
|
||||||
|
content: '{}'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawInput = JSON.stringify(input);
|
||||||
|
const result = runHook(input);
|
||||||
|
assert.strictEqual(result.code, 0, `Expected exit 0 for ENOENT path, got ${result.code}; stderr: ${result.stderr}`);
|
||||||
|
assert.strictEqual(result.stdout, rawInput, 'Expected raw passthrough when path does not exist');
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||||
|
} catch {
|
||||||
|
// best-effort cleanup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
|
||||||
|
if (
|
||||||
|
test('blocks protected paths that exist as a dangling symlink', () => {
|
||||||
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
|
||||||
|
try {
|
||||||
|
const missingTarget = path.join(tmpDir, 'nowhere.js');
|
||||||
|
const linkPath = path.join(tmpDir, '.eslintrc.js');
|
||||||
|
try {
|
||||||
|
fs.symlinkSync(missingTarget, linkPath);
|
||||||
|
} catch (err) {
|
||||||
|
// Windows without Developer Mode or certain sandboxes disallow
|
||||||
|
// symlinks. Skip cleanly rather than fail the suite.
|
||||||
|
if (err.code === 'EPERM' || err.code === 'EACCES') {
|
||||||
|
console.log(' (skipped: symlink creation not permitted here)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const input = {
|
||||||
|
tool_name: 'Write',
|
||||||
|
tool_input: {
|
||||||
|
file_path: linkPath,
|
||||||
|
content: 'module.exports = {};'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = runHook(input);
|
||||||
|
assert.strictEqual(result.code, 2, `Expected exit 2 for dangling symlink, got ${result.code}; stderr: ${result.stderr}`);
|
||||||
|
assert.strictEqual(result.stdout, '', 'Blocked hook should not echo raw input');
|
||||||
|
assert.ok(
|
||||||
|
result.stderr.includes('BLOCKED: Modifying .eslintrc.js is not allowed.'),
|
||||||
|
`Expected block message, got: ${result.stderr}`
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||||
|
} catch {
|
||||||
|
// best-effort cleanup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
|
||||||
|
if (
|
||||||
|
test('still blocks writes to an existing protected config file', () => {
|
||||||
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-config-protect-'));
|
||||||
|
try {
|
||||||
|
const absPath = path.join(tmpDir, '.eslintrc.js');
|
||||||
|
fs.writeFileSync(absPath, 'module.exports = { rules: {} };');
|
||||||
|
|
||||||
|
const input = {
|
||||||
|
tool_name: 'Edit',
|
||||||
|
tool_input: {
|
||||||
|
file_path: absPath,
|
||||||
|
content: 'module.exports = { rules: { "no-console": "off" } };'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = runHook(input);
|
||||||
|
assert.strictEqual(result.code, 2, 'Expected exit 2 when modifying an existing protected config');
|
||||||
|
assert.strictEqual(result.stdout, '', 'Blocked hook should not echo raw input');
|
||||||
|
assert.ok(result.stderr.includes('BLOCKED: Modifying .eslintrc.js is not allowed.'), `Expected block message, got: ${result.stderr}`);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||||
|
} catch {
|
||||||
|
// best-effort cleanup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
|
||||||
|
if (
|
||||||
|
test('legacy hooks do not echo raw input when they fail without stdout', () => {
|
||||||
|
const pluginRoot = path.join(__dirname, '..', `tmp-runner-plugin-${Date.now()}`);
|
||||||
|
const scriptDir = path.join(pluginRoot, 'scripts', 'hooks');
|
||||||
|
const scriptPath = path.join(scriptDir, 'legacy-block.js');
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(scriptDir, { recursive: true });
|
||||||
|
fs.writeFileSync(scriptPath, '#!/usr/bin/env node\nprocess.stderr.write("blocked by legacy hook\\n");\nprocess.exit(2);\n');
|
||||||
|
|
||||||
|
const rawInput = JSON.stringify({
|
||||||
|
tool_name: 'Write',
|
||||||
|
tool_input: {
|
||||||
|
file_path: '.eslintrc.js',
|
||||||
|
content: 'module.exports = {};'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = runCustomHook(pluginRoot, 'pre:legacy-block', 'scripts/hooks/legacy-block.js', rawInput);
|
||||||
|
assert.strictEqual(result.code, 2, 'Expected failing legacy hook exit code to propagate');
|
||||||
|
assert.strictEqual(result.stdout, '', 'Expected failing legacy hook to avoid raw passthrough');
|
||||||
|
assert.ok(result.stderr.includes('blocked by legacy hook'), `Expected legacy hook stderr, got: ${result.stderr}`);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
||||||
|
} catch {
|
||||||
|
// best-effort cleanup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
passed++;
|
||||||
|
else failed++;
|
||||||
|
|
||||||
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
||||||
process.exit(failed > 0 ? 1 : 0);
|
process.exit(failed > 0 ? 1 : 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user