memento-mori-jester 0.1.74 → 0.1.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/ROADMAP.md +4 -2
- package/docs/DEMO.md +2 -2
- package/docs/MAINTAINER_TRIAGE.md +2 -1
- package/docs/PRODUCTION_READINESS.md +1 -1
- package/docs/RELEASE.md +1 -0
- package/docs/RELEASE_NOTES_v0.1.75.md +42 -0
- package/docs/RELEASE_NOTES_v0.1.76.md +43 -0
- package/examples/fixtures/README.md +3 -1
- package/examples/fixtures/preset-review-cases.json +122 -0
- package/package.json +1 -1
- package/scripts/check-production-readiness.mjs +4 -0
- package/scripts/report-fixtures.mjs +228 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to Memento Mori Jester are tracked here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.1.76
|
|
8
|
+
|
|
9
|
+
- Added eight real-world quiet-pass fixtures across python, security, web, and AI preset slices, growing the corpus to 216 fixtures.
|
|
10
|
+
- Strengthened safe near-miss evidence for Pydantic parsing, Pyright checks, SBOM generation, vulnerability-report docs, escaped React rendering, session-cookie docs, model regression checks, and static action allowlists.
|
|
11
|
+
- Refreshed demo, roadmap, fixture docs, and release notes for the expanded preset curation batch.
|
|
12
|
+
|
|
13
|
+
## 0.1.75
|
|
14
|
+
|
|
15
|
+
- Added `npm run fixtures:report -- --markdown` for paste-ready fixture coverage snapshots.
|
|
16
|
+
- Added Markdown tables for totals, counts, rule-family slices, preset slices, gaps, quiet-pass coverage, curation-next guidance, and next commands.
|
|
17
|
+
- Updated maintainer docs, release docs, and production-readiness checks for the Markdown fixture report export.
|
|
18
|
+
|
|
7
19
|
## 0.1.74
|
|
8
20
|
|
|
9
21
|
- Added six API quiet-pass fixtures, growing the corpus to 208 fixtures.
|
package/README.md
CHANGED
|
@@ -501,7 +501,7 @@ Use the false-positive template for noisy cautions or blocks. Include `jester su
|
|
|
501
501
|
|
|
502
502
|
Maintainers can use [docs/MAINTAINER_TRIAGE.md](docs/MAINTAINER_TRIAGE.md) to turn useful false-positive reports into redacted fixtures.
|
|
503
503
|
Run `npm run fixtures:check` before merging fixture changes; it catches duplicate IDs, missing rule metadata, weak descriptions, unsafe-looking content, and duplicate content.
|
|
504
|
-
Run `npm run fixtures:report` to see fixture coverage by rule, rule family, preset slice, kind, verdict, quiet-pass boundaries, feasible pass-case gaps, and curation-next guidance before choosing the next fixture.
|
|
504
|
+
Run `npm run fixtures:report` to see fixture coverage by rule, rule family, preset slice, kind, verdict, quiet-pass boundaries, feasible pass-case gaps, and curation-next guidance before choosing the next fixture. Use `npm run fixtures:report -- --markdown` when you want a paste-ready summary for release notes or GitHub issues.
|
|
505
505
|
|
|
506
506
|
For vulnerabilities, private code exposure, or credential-handling concerns, follow [SECURITY.md](SECURITY.md) instead of opening a public issue with sensitive details.
|
|
507
507
|
|
package/ROADMAP.md
CHANGED
|
@@ -6,6 +6,8 @@ Memento Mori Jester is usable today as a CLI, MCP server, GitHub Action, and git
|
|
|
6
6
|
|
|
7
7
|
## Recently Shipped
|
|
8
8
|
|
|
9
|
+
- Real-world preset quiet-pass curation in v0.1.76, adding eight safe examples across python, security, web, and AI workflows while keeping fixture coverage gaps clean.
|
|
10
|
+
- Markdown fixture report export in v0.1.75 for paste-ready coverage snapshots in release notes, GitHub issues, and maintainer updates.
|
|
9
11
|
- API fixture curation in v0.1.74, adding six quiet-pass examples for schema parsing, query-builder filters, enabled rate limiting, read-only Prisma migration diffs, signed-webhook docs, and OpenAPI schema docs.
|
|
10
12
|
- Web/AI fixture curation in v0.1.73, adding six quiet-pass examples for safe text rendering, allowlisted target paths, public analytics IDs, model-check commands, tool allowlist checks, and public model-name config.
|
|
11
13
|
- Python/security fixture curation in v0.1.72, adding six quiet-pass examples for Bandit, pip-audit, coverage/pytest, Trivy, npm audit, and TLS verification-enabled diffs.
|
|
@@ -63,9 +65,9 @@ Memento Mori Jester is usable today as a CLI, MCP server, GitHub Action, and git
|
|
|
63
65
|
|
|
64
66
|
## Product Ideas
|
|
65
67
|
|
|
66
|
-
- Collect real-world reports for the next lowest-count preset slices
|
|
68
|
+
- Collect real-world reports for the next lowest-count preset slices now highlighted by `fixtures:report`.
|
|
67
69
|
- Add more framework-specific false-positive examples from real reports so tuning guidance keeps getting sharper.
|
|
68
|
-
- Add a
|
|
70
|
+
- Add a promo/share kit with X post copy, still images, and a simple sharing checklist.
|
|
69
71
|
|
|
70
72
|
## Quality And Safety
|
|
71
73
|
|
package/docs/DEMO.md
CHANGED
|
@@ -353,9 +353,9 @@ Preset packs:
|
|
|
353
353
|
|
|
354
354
|
## 13. Review Fixtures
|
|
355
355
|
|
|
356
|
-
The fixture suite in `examples/fixtures/preset-review-cases.json` captures small real-usage examples with expected `pass`, `caution`, or `block` verdicts. It also includes matched-pass examples for low-severity rules, quiet-pass `absentRuleIds` examples that prove noisy rules stay silent for safe near-misses, stack-specific coverage for every built-in preset, quiet-pass boundaries across built-in, structural, custom, and preset/config-derived rules, second firing examples for preset blocked-command rules, second examples for AI/API, framework custom, built-in, and configured sensitive-domain rules, AI tool-dispatch examples with safe allowlist/schema boundaries, and real-world low-count preset examples across node, python, web, infra, AI, and security slices. Recent quiet-pass examples cover typechecks, prebuild scripts, mypy, dataclass parsing, CodeQL, Dependabot limits, form validation, accessibility copy, read-only Kubernetes inspection, Docker disk usage, Terraform linting, public-IP hardening changes, npm audit/outdated/ci, development-mode Node commands, package export maps, workspace test scripts, Bandit, pip-audit, coverage/pytest, Trivy filesystem scans, npm audit, TLS verification-enabled diffs, safe text rendering, allowlisted target paths, public analytics IDs, model-check commands, tool allowlist checks, public model-name config, API schema parsing, query-builder filters, enabled rate limiting, read-only Prisma migration diffs, signed-webhook docs,
|
|
356
|
+
The fixture suite in `examples/fixtures/preset-review-cases.json` captures small real-usage examples with expected `pass`, `caution`, or `block` verdicts. It also includes matched-pass examples for low-severity rules, quiet-pass `absentRuleIds` examples that prove noisy rules stay silent for safe near-misses, stack-specific coverage for every built-in preset, quiet-pass boundaries across built-in, structural, custom, and preset/config-derived rules, second firing examples for preset blocked-command rules, second examples for AI/API, framework custom, built-in, and configured sensitive-domain rules, AI tool-dispatch examples with safe allowlist/schema boundaries, and real-world low-count preset examples across node, python, web, infra, AI, and security slices. Recent quiet-pass examples cover typechecks, prebuild scripts, mypy, dataclass parsing, CodeQL, Dependabot limits, form validation, accessibility copy, read-only Kubernetes inspection, Docker disk usage, Terraform linting, public-IP hardening changes, npm audit/outdated/ci, development-mode Node commands, package export maps, workspace test scripts, Bandit, pip-audit, coverage/pytest, Trivy filesystem scans, npm audit, TLS verification-enabled diffs, safe text rendering, allowlisted target paths, public analytics IDs, model-check commands, tool allowlist checks, public model-name config, API schema parsing, query-builder filters, enabled rate limiting, read-only Prisma migration diffs, signed-webhook docs, OpenAPI schema docs, Pydantic parsing, Pyright checks, SBOM generation, vulnerability-report docs, escaped React rendering, session-cookie docs, model regression checks, and static action allowlists. These examples are run by `npm test`, so preset tuning changes stay visible.
|
|
357
357
|
|
|
358
|
-
Maintainers can run `npm run fixtures:report` to see coverage by verdict, kind, preset, rule family, and preset slice. The report also includes a `Curation next` section that points at the next useful fixture batch, such as thin rules, feasible pass-case evidence, rule-family gaps, or lower-count presets.
|
|
358
|
+
Maintainers can run `npm run fixtures:report` to see coverage by verdict, kind, preset, rule family, and preset slice. The report also includes a `Curation next` section that points at the next useful fixture batch, such as thin rules, feasible pass-case evidence, rule-family gaps, or lower-count presets. Use `npm run fixtures:report -- --markdown` for a paste-ready version of the same snapshot.
|
|
359
359
|
|
|
360
360
|
Maintainers can use `docs/MAINTAINER_TRIAGE.md` to turn useful false-positive reports into redacted fixture cases.
|
|
361
361
|
|
|
@@ -77,13 +77,14 @@ npm.cmd test
|
|
|
77
77
|
npm.cmd run fixtures:check
|
|
78
78
|
npm.cmd run fixtures:report
|
|
79
79
|
npm.cmd run fixtures:report -- --json
|
|
80
|
+
npm.cmd run fixtures:report -- --markdown
|
|
80
81
|
node .\dist\cli.js tune <rule-id>
|
|
81
82
|
node .\dist\cli.js tune <rule-id> --json
|
|
82
83
|
node .\dist\cli.js tune coverage
|
|
83
84
|
```
|
|
84
85
|
|
|
85
86
|
5. Fix any duplicate IDs, missing expected rule metadata, weak descriptions, unsafe content, or duplicate content reported by `fixtures:check`.
|
|
86
|
-
6. Use `fixtures:report` to check whether the change improves feasible pass-case, quiet-pass, preset, kind, rule-family, or verdict coverage. Start with the report's `Curation next` section when deciding which fixture batch to add first.
|
|
87
|
+
6. Use `fixtures:report` to check whether the change improves feasible pass-case, quiet-pass, preset, kind, rule-family, or verdict coverage. Start with the report's `Curation next` section when deciding which fixture batch to add first, and use `fixtures:report -- --markdown` when you need a paste-ready snapshot for an issue or release note.
|
|
87
88
|
7. Check whether support/confidence changed in the expected direction.
|
|
88
89
|
8. If the fixture changes verdict behavior, mention the exact rule impact in `CHANGELOG.md`.
|
|
89
90
|
|
|
@@ -53,7 +53,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
|
|
|
53
53
|
- `SECURITY.md` routes vulnerability reports away from public issues and asks for redacted diagnostics.
|
|
54
54
|
- `docs/MAINTAINER_TRIAGE.md` explains how to turn useful false-positive reports into fixture coverage before changing rule logic.
|
|
55
55
|
- `npm run fixtures:check` validates fixture IDs, metadata, unsafe-looking content, duplicate content, and explicit expected/absent rule intent.
|
|
56
|
-
- `npm run fixtures:report` shows fixture coverage by rule, rule family, preset slice, kind, verdict, quiet-pass rule boundaries, and feasible pass-case gaps so maintainers can pick the next fixture target.
|
|
56
|
+
- `npm run fixtures:report` shows fixture coverage by rule, rule family, preset slice, kind, verdict, quiet-pass rule boundaries, and feasible pass-case gaps so maintainers can pick the next fixture target; `npm run fixtures:report -- --markdown` produces a paste-ready maintainer snapshot.
|
|
57
57
|
- npm publish has a manual workflow fallback, but the normal release path is tag-driven trusted publishing.
|
|
58
58
|
|
|
59
59
|
## Static Guard
|
package/docs/RELEASE.md
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Memento Mori Jester v0.1.75
|
|
2
|
+
|
|
3
|
+
This release adds a Markdown export for the fixture coverage report so maintainers can paste stable quality snapshots into release notes, GitHub issues, and project updates. Review behavior is unchanged.
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
- Added `npm run fixtures:report -- --markdown`.
|
|
8
|
+
- Added Markdown sections for:
|
|
9
|
+
- summary totals.
|
|
10
|
+
- verdict, kind, and preset counts.
|
|
11
|
+
- rule-family slices.
|
|
12
|
+
- preset slices.
|
|
13
|
+
- gap sections.
|
|
14
|
+
- quiet-pass rule coverage.
|
|
15
|
+
- quiet-pass fixture samples.
|
|
16
|
+
- curation-next guidance.
|
|
17
|
+
- next commands.
|
|
18
|
+
- Added a guard that rejects combining `--json` and `--markdown`.
|
|
19
|
+
- Updated maintainer docs, release docs, demo docs, README support notes, and production-readiness checks.
|
|
20
|
+
|
|
21
|
+
## Public Interface
|
|
22
|
+
|
|
23
|
+
- New maintainer script mode: `npm run fixtures:report -- --markdown`.
|
|
24
|
+
- No CLI command changes.
|
|
25
|
+
- No config schema changes.
|
|
26
|
+
- No rule matching, scoring, or verdict behavior changes.
|
|
27
|
+
- No MCP, playground, GitHub Action, or npm publishing changes.
|
|
28
|
+
|
|
29
|
+
## Release Validation
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
npm.cmd test
|
|
33
|
+
npm.cmd run demo:svg:check
|
|
34
|
+
npm.cmd run fixtures:report
|
|
35
|
+
npm.cmd run fixtures:report -- --json
|
|
36
|
+
npm.cmd run fixtures:report -- --markdown
|
|
37
|
+
npm.cmd run pack:dry
|
|
38
|
+
git diff --check
|
|
39
|
+
node .\dist\cli.js tune coverage --no-config
|
|
40
|
+
node .\dist\cli.js tune risky-domain --json --no-config
|
|
41
|
+
git diff | node .\dist\cli.js diff --fail-on block --subject "v0.1.75 markdown fixture report export"
|
|
42
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Memento Mori Jester v0.1.76
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
This release expands the real-world quiet-pass fixture corpus for the lowest-count preset slices: `python`, `security`, `web`, and `ai`.
|
|
6
|
+
|
|
7
|
+
## What Changed
|
|
8
|
+
|
|
9
|
+
- Added eight pass fixtures, growing the fixture suite from 208 to 216 cases.
|
|
10
|
+
- Added python safe-boundary examples for Pydantic model validation and Pyright type checks.
|
|
11
|
+
- Added security safe-boundary examples for SBOM generation and vulnerability-report documentation.
|
|
12
|
+
- Added web safe-boundary examples for escaped React rendering and docs-only session-cookie guidance.
|
|
13
|
+
- Added AI safe-boundary examples for model regression checks and static action allowlists.
|
|
14
|
+
- Refreshed the fixture docs, demo transcript, changelog, and roadmap.
|
|
15
|
+
|
|
16
|
+
## Public Interface
|
|
17
|
+
|
|
18
|
+
- No CLI command changes.
|
|
19
|
+
- No MCP tool changes.
|
|
20
|
+
- No config schema changes.
|
|
21
|
+
- No review rule, scoring, or verdict behavior changes.
|
|
22
|
+
- Fixture reports now reflect 216 total fixtures and the updated preset counts.
|
|
23
|
+
|
|
24
|
+
## Release Validation
|
|
25
|
+
|
|
26
|
+
```powershell
|
|
27
|
+
npm.cmd test
|
|
28
|
+
npm.cmd run demo:svg:check
|
|
29
|
+
npm.cmd run fixtures:report
|
|
30
|
+
npm.cmd run fixtures:report -- --json
|
|
31
|
+
npm.cmd run fixtures:report -- --markdown
|
|
32
|
+
npm.cmd run pack:dry
|
|
33
|
+
git diff --check
|
|
34
|
+
git diff | node .\dist\cli.js diff --fail-on block --subject "v0.1.76 real-world preset quiet-pass curation"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Expected fixture report checks:
|
|
38
|
+
|
|
39
|
+
- `Fixtures: 216`
|
|
40
|
+
- no thin rule coverage
|
|
41
|
+
- no preset/kind gaps
|
|
42
|
+
- no rules without quiet-pass coverage
|
|
43
|
+
- deterministic `Curation next` guidance
|
|
@@ -29,6 +29,7 @@ Maintainer triage guidance lives in [docs/MAINTAINER_TRIAGE.md](../../docs/MAINT
|
|
|
29
29
|
- Quiet-pass examples for Bandit, pip-audit, coverage/pytest, Trivy filesystem scans, npm audit, and TLS verification-enabled diffs.
|
|
30
30
|
- Quiet-pass examples for safe text rendering, allowlisted target paths, public analytics IDs, model-check commands, tool allowlist checks, and public model-name config.
|
|
31
31
|
- Quiet-pass examples for API schema parsing, query-builder filters, enabled rate limiting, read-only Prisma migration diffs, signed-webhook docs, and OpenAPI schema docs.
|
|
32
|
+
- Quiet-pass examples for Pydantic parsing, Pyright checks, SBOM generation, vulnerability-report docs, escaped React rendering, session-cookie docs, model regression checks, and static action allowlists.
|
|
32
33
|
- Fixture metadata like `weight` and `edgeCase` to support precision-weighted tuning evidence.
|
|
33
34
|
|
|
34
35
|
## Local Check
|
|
@@ -38,6 +39,7 @@ npm.cmd test
|
|
|
38
39
|
npm.cmd run fixtures:check
|
|
39
40
|
npm.cmd run fixtures:report
|
|
40
41
|
npm.cmd run fixtures:report -- --json
|
|
42
|
+
npm.cmd run fixtures:report -- --markdown
|
|
41
43
|
```
|
|
42
44
|
|
|
43
45
|
For one-off manual review, paste a fixture `content` value into:
|
|
@@ -63,4 +65,4 @@ Do not add secrets, private code, customer data, complete logs, or machine-speci
|
|
|
63
65
|
|
|
64
66
|
`npm run fixtures:report` summarizes coverage by rule, rule family, preset slice, review kind, verdict, and quiet-pass rule boundaries. Use it to find rules without pass-case coverage, pass-eligible rules without pass-case coverage, rules without quiet-pass coverage, thin rule coverage, preset/kind gaps, quiet pass fixtures, and the next curation target.
|
|
65
67
|
|
|
66
|
-
The `Curation next` section is a maintainer shortcut: start there when deciding whether the next fixture batch should focus on thin rules, feasible pass-case evidence, a specific rule family, or lower-count presets. The `--json` output includes the same `ruleFamilySlices`, `presetSlices`, `passEligibleRulesWithoutPassCases`, and `curationNext` fields for scripts.
|
|
68
|
+
The `Curation next` section is a maintainer shortcut: start there when deciding whether the next fixture batch should focus on thin rules, feasible pass-case evidence, a specific rule family, or lower-count presets. The `--json` output includes the same `ruleFamilySlices`, `presetSlices`, `passEligibleRulesWithoutPassCases`, and `curationNext` fields for scripts. The `--markdown` output renders the same snapshot as paste-ready Markdown tables for release notes, GitHub issues, or maintainer updates.
|
|
@@ -2737,5 +2737,127 @@
|
|
|
2737
2737
|
"absentRuleIds": [
|
|
2738
2738
|
"configured-sensitive-domain-openapi"
|
|
2739
2739
|
]
|
|
2740
|
+
},
|
|
2741
|
+
{
|
|
2742
|
+
"id": "python-pydantic-parse-diff-pass",
|
|
2743
|
+
"preset": "python",
|
|
2744
|
+
"kind": "diff",
|
|
2745
|
+
"description": "Pydantic model validation should stay quiet around Python dynamic execution checks.",
|
|
2746
|
+
"content": "diff --git a/app/settings.py b/app/settings.py\n--- a/app/settings.py\n+++ b/app/settings.py\n@@ -1 +1,2 @@\n+settings = SettingsModel.model_validate(raw_settings)\n",
|
|
2747
|
+
"expectedVerdict": "pass",
|
|
2748
|
+
"weight": 2,
|
|
2749
|
+
"expectedRuleIds": [],
|
|
2750
|
+
"absentRuleIds": [
|
|
2751
|
+
"custom-python-eval-exec",
|
|
2752
|
+
"custom-python-pickle-load"
|
|
2753
|
+
]
|
|
2754
|
+
},
|
|
2755
|
+
{
|
|
2756
|
+
"id": "python-pyright-command-pass",
|
|
2757
|
+
"preset": "python",
|
|
2758
|
+
"kind": "command",
|
|
2759
|
+
"description": "Python type-check commands should not trip eval, pickle, or unsafe package checks.",
|
|
2760
|
+
"content": "python -m pyright app tests",
|
|
2761
|
+
"expectedVerdict": "pass",
|
|
2762
|
+
"weight": 2,
|
|
2763
|
+
"expectedRuleIds": [],
|
|
2764
|
+
"absentRuleIds": [
|
|
2765
|
+
"blocked-command-pip-install-break-system-packages",
|
|
2766
|
+
"custom-python-eval-exec",
|
|
2767
|
+
"custom-python-pickle-load"
|
|
2768
|
+
]
|
|
2769
|
+
},
|
|
2770
|
+
{
|
|
2771
|
+
"id": "sec-sbom-command-pass",
|
|
2772
|
+
"preset": "security",
|
|
2773
|
+
"kind": "command",
|
|
2774
|
+
"description": "SBOM generation commands should stay quiet around security preset danger checks.",
|
|
2775
|
+
"content": "syft dir:. -o cyclonedx-json > sbom.json",
|
|
2776
|
+
"expectedVerdict": "pass",
|
|
2777
|
+
"weight": 2,
|
|
2778
|
+
"expectedRuleIds": [],
|
|
2779
|
+
"absentRuleIds": [
|
|
2780
|
+
"blocked-command-chmod-r-777",
|
|
2781
|
+
"custom-broad-cors",
|
|
2782
|
+
"custom-insecure-tls-disabled",
|
|
2783
|
+
"secret-material"
|
|
2784
|
+
]
|
|
2785
|
+
},
|
|
2786
|
+
{
|
|
2787
|
+
"id": "sec-vulnerability-report-docs-pass",
|
|
2788
|
+
"preset": "security",
|
|
2789
|
+
"kind": "diff",
|
|
2790
|
+
"description": "Docs for vulnerability reports should stay quiet when they only say not to paste sensitive material.",
|
|
2791
|
+
"content": "diff --git a/docs/VULNERABILITY_REPORTS.md b/docs/VULNERABILITY_REPORTS.md\n--- a/docs/VULNERABILITY_REPORTS.md\n+++ b/docs/VULNERABILITY_REPORTS.md\n@@ -1 +1,2 @@\n+Ask reporters to redact tokens, private keys, and exploit logs before filing public issues.\n",
|
|
2792
|
+
"expectedVerdict": "pass",
|
|
2793
|
+
"edgeCase": true,
|
|
2794
|
+
"weight": 1,
|
|
2795
|
+
"expectedRuleIds": [],
|
|
2796
|
+
"absentRuleIds": [
|
|
2797
|
+
"configured-sensitive-domain-token",
|
|
2798
|
+
"configured-sensitive-domain-private-key",
|
|
2799
|
+
"secret-material"
|
|
2800
|
+
]
|
|
2801
|
+
},
|
|
2802
|
+
{
|
|
2803
|
+
"id": "web-react-escaped-output-diff-pass",
|
|
2804
|
+
"preset": "web",
|
|
2805
|
+
"kind": "diff",
|
|
2806
|
+
"description": "Escaped React text rendering should not trip unsafe HTML injection checks.",
|
|
2807
|
+
"content": "diff --git a/src/components/UserName.tsx b/src/components/UserName.tsx\n--- a/src/components/UserName.tsx\n+++ b/src/components/UserName.tsx\n@@ -1 +1,2 @@\n+return <span>{displayName}</span>;\n",
|
|
2808
|
+
"expectedVerdict": "pass",
|
|
2809
|
+
"weight": 2,
|
|
2810
|
+
"expectedRuleIds": [],
|
|
2811
|
+
"absentRuleIds": [
|
|
2812
|
+
"custom-web-unsafe-html-injection",
|
|
2813
|
+
"configured-sensitive-domain-dangerouslysetinnerhtml",
|
|
2814
|
+
"configured-sensitive-domain-innerhtml"
|
|
2815
|
+
]
|
|
2816
|
+
},
|
|
2817
|
+
{
|
|
2818
|
+
"id": "web-session-cookie-docs-pass",
|
|
2819
|
+
"preset": "web",
|
|
2820
|
+
"kind": "diff",
|
|
2821
|
+
"description": "Docs-only browser session guidance should not trip storage, redirect, or cookie noise.",
|
|
2822
|
+
"content": "diff --git a/docs/WEB_SESSIONS.md b/docs/WEB_SESSIONS.md\n--- a/docs/WEB_SESSIONS.md\n+++ b/docs/WEB_SESSIONS.md\n@@ -1 +1,2 @@\n+Prefer httpOnly cookies for sessions and keep redirects limited to same-origin paths.\n",
|
|
2823
|
+
"expectedVerdict": "pass",
|
|
2824
|
+
"edgeCase": true,
|
|
2825
|
+
"weight": 1,
|
|
2826
|
+
"expectedRuleIds": [],
|
|
2827
|
+
"absentRuleIds": [
|
|
2828
|
+
"configured-sensitive-domain-cookies",
|
|
2829
|
+
"configured-sensitive-domain-redirect",
|
|
2830
|
+
"configured-sensitive-domain-session",
|
|
2831
|
+
"custom-web-open-redirect-shape",
|
|
2832
|
+
"custom-web-storage-sensitive-value",
|
|
2833
|
+
"risky-domain"
|
|
2834
|
+
]
|
|
2835
|
+
},
|
|
2836
|
+
{
|
|
2837
|
+
"id": "ai-model-regression-command-pass",
|
|
2838
|
+
"preset": "ai",
|
|
2839
|
+
"kind": "command",
|
|
2840
|
+
"description": "Running model regression checks should not look like skipped AI safety checks.",
|
|
2841
|
+
"content": "npm run model:checks -- --suite prompt-regression",
|
|
2842
|
+
"expectedVerdict": "pass",
|
|
2843
|
+
"weight": 2,
|
|
2844
|
+
"expectedRuleIds": [],
|
|
2845
|
+
"absentRuleIds": [
|
|
2846
|
+
"custom-ai-evals-skipped"
|
|
2847
|
+
]
|
|
2848
|
+
},
|
|
2849
|
+
{
|
|
2850
|
+
"id": "ai-tool-registry-allowlist-diff-pass",
|
|
2851
|
+
"preset": "ai",
|
|
2852
|
+
"kind": "diff",
|
|
2853
|
+
"description": "Static action allowlists should not trip user-controlled dispatch checks.",
|
|
2854
|
+
"content": "diff --git a/src/actions/registry.ts b/src/actions/registry.ts\n--- a/src/actions/registry.ts\n+++ b/src/actions/registry.ts\n@@ -1 +1,2 @@\n+export const allowedActions = new Set([\"search_docs\", \"summarize_ticket\"]);\n",
|
|
2855
|
+
"expectedVerdict": "pass",
|
|
2856
|
+
"weight": 2,
|
|
2857
|
+
"expectedRuleIds": [],
|
|
2858
|
+
"absentRuleIds": [
|
|
2859
|
+
"custom-ai-user-controlled-tool-dispatch",
|
|
2860
|
+
"custom-ai-model-output-execution"
|
|
2861
|
+
]
|
|
2740
2862
|
}
|
|
2741
2863
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memento-mori-jester",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.76",
|
|
4
4
|
"description": "A local court-jester sidecar for AI coding agents: review plans, commands, diffs, and final claims before they get too pleased with themselves.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -94,6 +94,7 @@ requireText("README.md", /false-positive/i, "false-positive support guidance");
|
|
|
94
94
|
requireText("README.md", /MAINTAINER_TRIAGE\.md/, "maintainer triage guide link");
|
|
95
95
|
requireText("README.md", /fixtures:check/, "fixture authoring check guidance");
|
|
96
96
|
requireText("README.md", /fixtures:report/, "fixture coverage report guidance");
|
|
97
|
+
requireText("README.md", /fixtures:report -- --markdown/, "Markdown fixture report guidance");
|
|
97
98
|
requireText("README.md", /License: PolyForm Noncommercial/, "the noncommercial license badge");
|
|
98
99
|
requireText("docs/PRODUCTION_READINESS.md", /npm package/i, "npm package readiness");
|
|
99
100
|
requireText("docs/PRODUCTION_READINESS.md", /GitHub Action/i, "GitHub Action readiness");
|
|
@@ -106,6 +107,7 @@ requireText("docs/PRODUCTION_READINESS.md", /issue templates/i, "issue template
|
|
|
106
107
|
requireText("docs/PRODUCTION_READINESS.md", /MAINTAINER_TRIAGE\.md/, "maintainer triage readiness");
|
|
107
108
|
requireText("docs/PRODUCTION_READINESS.md", /fixtures:check/, "fixture authoring check readiness");
|
|
108
109
|
requireText("docs/PRODUCTION_READINESS.md", /fixtures:report/, "fixture coverage report readiness");
|
|
110
|
+
requireText("docs/PRODUCTION_READINESS.md", /fixtures:report -- --markdown/, "Markdown fixture report readiness");
|
|
109
111
|
requireText("docs/PRODUCTION_READINESS.md", /quiet-pass/, "quiet-pass fixture readiness");
|
|
110
112
|
requireText("docs/CLI.md", /jester doctor --json/, "doctor JSON CLI docs");
|
|
111
113
|
requireText("docs/CLI.md", /quiet-pass fixture/, "quiet-pass fixture CLI docs");
|
|
@@ -118,6 +120,7 @@ requireText("examples/fixtures/README.md", /MAINTAINER_TRIAGE\.md/, "maintainer
|
|
|
118
120
|
requireText("examples/fixtures/README.md", /Adding A Fixture From A Report/, "fixture report conversion guidance");
|
|
119
121
|
requireText("examples/fixtures/README.md", /fixtures:check/, "fixture authoring check guidance");
|
|
120
122
|
requireText("examples/fixtures/README.md", /fixtures:report/, "fixture coverage report guidance");
|
|
123
|
+
requireText("examples/fixtures/README.md", /fixtures:report -- --markdown/, "Markdown fixture report guidance");
|
|
121
124
|
requireText("scripts/check-fixtures.mjs", /duplicated/, "duplicate fixture id check");
|
|
122
125
|
requireText("scripts/check-fixtures.mjs", /unsafeContentPatterns/, "unsafe fixture content checks");
|
|
123
126
|
forbidText("scripts/check-fixtures.mjs", /src\/config\.ts|src\/types\.ts/, "source-only fixture validator dependencies");
|
|
@@ -125,6 +128,7 @@ requireText("scripts/report-fixtures.mjs", /rulesWithoutPassCases/, "rules witho
|
|
|
125
128
|
requireText("scripts/report-fixtures.mjs", /rulesWithoutQuietPassCoverage/, "rules without quiet-pass coverage report");
|
|
126
129
|
requireText("scripts/report-fixtures.mjs", /quietPassRuleCoverage/, "quiet-pass rule coverage report");
|
|
127
130
|
requireText("scripts/report-fixtures.mjs", /presetKindGaps/, "preset and kind gap report");
|
|
131
|
+
requireText("scripts/report-fixtures.mjs", /--markdown/, "Markdown fixture report output");
|
|
128
132
|
forbidText("scripts/report-fixtures.mjs", /src\/config\.ts|src\/types\.ts/, "source-only fixture report dependencies");
|
|
129
133
|
requireText("package.json", /"fixtures:check": "node scripts\/check-fixtures\.mjs"/, "fixture authoring check script");
|
|
130
134
|
requireText("package.json", /"fixtures:report": "node scripts\/report-fixtures\.mjs"/, "fixture coverage report script");
|
|
@@ -33,6 +33,12 @@ const ruleFamilyOrder = [
|
|
|
33
33
|
|
|
34
34
|
const args = new Set(process.argv.slice(2));
|
|
35
35
|
const json = args.has("--json");
|
|
36
|
+
const markdown = args.has("--markdown");
|
|
37
|
+
|
|
38
|
+
if (json && markdown) {
|
|
39
|
+
process.stderr.write("Use only one output format: --json or --markdown.\n");
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
36
42
|
|
|
37
43
|
function read(path) {
|
|
38
44
|
return readFileSync(join(root, path), "utf8");
|
|
@@ -55,6 +61,8 @@ const report = buildFixtureReport(fixtures);
|
|
|
55
61
|
|
|
56
62
|
if (json) {
|
|
57
63
|
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
64
|
+
} else if (markdown) {
|
|
65
|
+
process.stdout.write(renderFixtureReportMarkdown(report));
|
|
58
66
|
} else {
|
|
59
67
|
process.stdout.write(renderFixtureReport(report));
|
|
60
68
|
}
|
|
@@ -271,6 +279,91 @@ function renderFixtureReport(report) {
|
|
|
271
279
|
return `${lines.join("\n")}\n`;
|
|
272
280
|
}
|
|
273
281
|
|
|
282
|
+
function renderFixtureReportMarkdown(report) {
|
|
283
|
+
const lines = [
|
|
284
|
+
"# Fixture Coverage Report",
|
|
285
|
+
"",
|
|
286
|
+
"Generated from `examples/fixtures/preset-review-cases.json`.",
|
|
287
|
+
"",
|
|
288
|
+
"## Summary",
|
|
289
|
+
"",
|
|
290
|
+
"| Metric | Value |",
|
|
291
|
+
"| --- | ---: |",
|
|
292
|
+
`| Fixtures | ${report.totalFixtures} |`,
|
|
293
|
+
`| Weighted fixtures | ${report.totalWeight} |`,
|
|
294
|
+
`| Edge-case fixtures | ${report.edgeCaseFixtures} |`,
|
|
295
|
+
`| Rules covered by expectedRuleIds | ${report.rules.length} |`,
|
|
296
|
+
"",
|
|
297
|
+
"## Counts",
|
|
298
|
+
"",
|
|
299
|
+
"### By Verdict",
|
|
300
|
+
"",
|
|
301
|
+
...formatMarkdownCountTable("Verdict", report.byVerdict),
|
|
302
|
+
"",
|
|
303
|
+
"### By Kind",
|
|
304
|
+
"",
|
|
305
|
+
...formatMarkdownCountTable("Kind", report.byKind),
|
|
306
|
+
"",
|
|
307
|
+
"### By Preset",
|
|
308
|
+
"",
|
|
309
|
+
...formatMarkdownCountTable("Preset", report.byPreset),
|
|
310
|
+
"",
|
|
311
|
+
"## Rule Family Slices",
|
|
312
|
+
"",
|
|
313
|
+
...formatMarkdownRuleFamilyTable(report.ruleFamilySlices),
|
|
314
|
+
"",
|
|
315
|
+
"## Preset Slices",
|
|
316
|
+
"",
|
|
317
|
+
...formatMarkdownPresetTable(report.presetSlices),
|
|
318
|
+
"",
|
|
319
|
+
"## Gaps",
|
|
320
|
+
"",
|
|
321
|
+
"### Rules Without Pass-Case Coverage",
|
|
322
|
+
"",
|
|
323
|
+
...formatMarkdownRuleGapList(report.gaps.rulesWithoutPassCases),
|
|
324
|
+
"",
|
|
325
|
+
"### Pass-Eligible Rules Without Pass-Case Coverage",
|
|
326
|
+
"",
|
|
327
|
+
...formatMarkdownRuleGapList(report.gaps.passEligibleRulesWithoutPassCases),
|
|
328
|
+
"",
|
|
329
|
+
"### Rules Without Quiet-Pass Coverage",
|
|
330
|
+
"",
|
|
331
|
+
...formatMarkdownRuleGapList(report.gaps.rulesWithoutQuietPassCoverage),
|
|
332
|
+
"",
|
|
333
|
+
"### Thin Rule Coverage",
|
|
334
|
+
"",
|
|
335
|
+
...formatMarkdownRuleGapList(report.gaps.thinRuleCoverage),
|
|
336
|
+
"",
|
|
337
|
+
"### Preset/Kind Gaps",
|
|
338
|
+
"",
|
|
339
|
+
...formatMarkdownPresetKindGaps(report.gaps.presetKindGaps),
|
|
340
|
+
"",
|
|
341
|
+
"## Quiet-Pass Rule Coverage",
|
|
342
|
+
"",
|
|
343
|
+
...formatMarkdownQuietPassTable(report.gaps.quietPassRuleCoverage),
|
|
344
|
+
"",
|
|
345
|
+
"## Quiet-Pass Fixture Samples",
|
|
346
|
+
"",
|
|
347
|
+
...formatMarkdownFixtureSamples(report.gaps.quietPassFixtures),
|
|
348
|
+
"",
|
|
349
|
+
"## Curation Next",
|
|
350
|
+
"",
|
|
351
|
+
...formatMarkdownCurationNext(report.curationNext),
|
|
352
|
+
"",
|
|
353
|
+
"## Next Commands",
|
|
354
|
+
"",
|
|
355
|
+
"```powershell",
|
|
356
|
+
"npm run fixtures:check",
|
|
357
|
+
"npm run fixtures:report",
|
|
358
|
+
"npm run fixtures:report -- --json",
|
|
359
|
+
"npm run fixtures:report -- --markdown",
|
|
360
|
+
"node .\\dist\\cli.js tune coverage",
|
|
361
|
+
"```"
|
|
362
|
+
];
|
|
363
|
+
|
|
364
|
+
return `${lines.join("\n")}\n`;
|
|
365
|
+
}
|
|
366
|
+
|
|
274
367
|
function createRuleEntry(ruleId) {
|
|
275
368
|
return {
|
|
276
369
|
ruleId,
|
|
@@ -575,6 +668,141 @@ function formatCounts(counts) {
|
|
|
575
668
|
.join(", ");
|
|
576
669
|
}
|
|
577
670
|
|
|
671
|
+
function formatMarkdownCountTable(label, counts) {
|
|
672
|
+
return [
|
|
673
|
+
`| ${label} | Count |`,
|
|
674
|
+
"| --- | ---: |",
|
|
675
|
+
...Object.entries(counts).map(([key, value]) => `| ${markdownCell(key)} | ${value} |`)
|
|
676
|
+
];
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function formatMarkdownRuleFamilyTable(entries) {
|
|
680
|
+
if (entries.length === 0) {
|
|
681
|
+
return ["None."];
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return [
|
|
685
|
+
"| Family | Rules | Fixture Refs | Pass | Caution | Block | Quiet Pass | Thin |",
|
|
686
|
+
"| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |",
|
|
687
|
+
...entries.map((entry) =>
|
|
688
|
+
[
|
|
689
|
+
markdownCell(entry.family),
|
|
690
|
+
entry.ruleCount,
|
|
691
|
+
entry.fixtureReferences,
|
|
692
|
+
entry.passCases,
|
|
693
|
+
entry.cautionCases,
|
|
694
|
+
entry.blockCases,
|
|
695
|
+
entry.quietPassCases,
|
|
696
|
+
entry.thinRules.length
|
|
697
|
+
].join(" | ")
|
|
698
|
+
).map((row) => `| ${row} |`)
|
|
699
|
+
];
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
function formatMarkdownPresetTable(entries) {
|
|
703
|
+
if (entries.length === 0) {
|
|
704
|
+
return ["None."];
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return [
|
|
708
|
+
"| Preset | Fixtures | Weight | Pass | Caution | Block | Quiet Pass | Rule Refs | Absent Refs |",
|
|
709
|
+
"| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |",
|
|
710
|
+
...entries.map((entry) =>
|
|
711
|
+
[
|
|
712
|
+
markdownCell(entry.preset),
|
|
713
|
+
entry.total,
|
|
714
|
+
entry.weight,
|
|
715
|
+
entry.byVerdict.pass ?? 0,
|
|
716
|
+
entry.byVerdict.caution ?? 0,
|
|
717
|
+
entry.byVerdict.block ?? 0,
|
|
718
|
+
entry.quietPassFixtures,
|
|
719
|
+
entry.expectedRuleReferences,
|
|
720
|
+
entry.quietPassRuleReferences
|
|
721
|
+
].join(" | ")
|
|
722
|
+
).map((row) => `| ${row} |`)
|
|
723
|
+
];
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
function formatMarkdownRuleGapList(entries) {
|
|
727
|
+
if (entries.length === 0) {
|
|
728
|
+
return ["None."];
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
return entries
|
|
732
|
+
.slice(0, 12)
|
|
733
|
+
.map((entry) => `- \`${entry.ruleId}\`: ${entry.total} fixture(s), pass ${entry.passCases}, caution ${entry.cautionCases}, block ${entry.blockCases}, quiet-pass ${entry.quietPassCases}`);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function formatMarkdownPresetKindGaps(entries) {
|
|
737
|
+
if (entries.length === 0) {
|
|
738
|
+
return ["None."];
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
return entries.map((entry) => `- \`${entry.preset}\`: ${entry.missingKinds.map((kind) => `\`${kind}\``).join(", ")}`);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function formatMarkdownQuietPassTable(entries) {
|
|
745
|
+
if (entries.length === 0) {
|
|
746
|
+
return ["None."];
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
return [
|
|
750
|
+
"| Rule | Quiet-Pass Fixtures | Weight |",
|
|
751
|
+
"| --- | ---: | ---: |",
|
|
752
|
+
...entries
|
|
753
|
+
.slice(0, 12)
|
|
754
|
+
.map((entry) => `| \`${markdownCell(entry.ruleId)}\` | ${entry.total} | ${entry.weight} |`)
|
|
755
|
+
];
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function formatMarkdownFixtureSamples(entries) {
|
|
759
|
+
if (entries.length === 0) {
|
|
760
|
+
return ["None."];
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
return entries
|
|
764
|
+
.slice(0, 8)
|
|
765
|
+
.map((entry) => `- \`${entry.id}\`: ${markdownCell(entry.description)}`);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function formatMarkdownCurationNext(entries) {
|
|
769
|
+
if (entries.length === 0) {
|
|
770
|
+
return ["None."];
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
return [
|
|
774
|
+
"| Priority | Area | Count | Details |",
|
|
775
|
+
"| --- | --- | ---: | --- |",
|
|
776
|
+
...entries.map((entry) =>
|
|
777
|
+
`| ${markdownCell(entry.priority)} | ${markdownCell(entry.area)} | ${entry.count} | ${markdownCell(markdownCurationDetails(entry))} |`
|
|
778
|
+
)
|
|
779
|
+
];
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function markdownCurationDetails(entry) {
|
|
783
|
+
if (Array.isArray(entry.ruleIds) && entry.ruleIds.length > 0) {
|
|
784
|
+
return entry.ruleIds.join(", ");
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (Array.isArray(entry.details) && entry.details.length > 0) {
|
|
788
|
+
return entry.details.join("; ");
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (Array.isArray(entry.families) && entry.families.length > 0) {
|
|
792
|
+
return entry.families.map((family) => `${family.family} ${family.thinRules}`).join(", ");
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (Array.isArray(entry.presets) && entry.presets.length > 0) {
|
|
796
|
+
return entry.presets.map((preset) => `${preset.preset} ${preset.total}`).join(", ");
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
return "";
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function markdownCell(value) {
|
|
803
|
+
return String(value).replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
804
|
+
}
|
|
805
|
+
|
|
578
806
|
function formatRuleGaps(entries) {
|
|
579
807
|
if (entries.length === 0) {
|
|
580
808
|
return ["- none"];
|