@vyuhlabs/dxkit 2.4.7 → 2.5.0
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 +456 -30
- package/README.md +360 -439
- package/dist/analyzers/bom/gather.d.ts +3 -3
- package/dist/analyzers/bom/gather.js +3 -3
- package/dist/analyzers/bom/index.js +2 -2
- package/dist/analyzers/bom/index.js.map +1 -1
- package/dist/analyzers/dashboard/index.d.ts.map +1 -1
- package/dist/analyzers/dashboard/index.js +4 -3
- package/dist/analyzers/dashboard/index.js.map +1 -1
- package/dist/analyzers/developer/index.d.ts.map +1 -1
- package/dist/analyzers/developer/index.js +2 -1
- package/dist/analyzers/developer/index.js.map +1 -1
- package/dist/analyzers/dispatcher.d.ts +15 -0
- package/dist/analyzers/dispatcher.d.ts.map +1 -1
- package/dist/analyzers/dispatcher.js +42 -6
- package/dist/analyzers/dispatcher.js.map +1 -1
- package/dist/analyzers/health.d.ts.map +1 -1
- package/dist/analyzers/health.js +11 -1
- package/dist/analyzers/health.js.map +1 -1
- package/dist/analyzers/licenses/gather.d.ts +1 -1
- package/dist/analyzers/licenses/gather.d.ts.map +1 -1
- package/dist/analyzers/licenses/gather.js +18 -2
- package/dist/analyzers/licenses/gather.js.map +1 -1
- package/dist/analyzers/quality/index.d.ts.map +1 -1
- package/dist/analyzers/quality/index.js +10 -2
- package/dist/analyzers/quality/index.js.map +1 -1
- package/dist/analyzers/security/aggregator.d.ts.map +1 -1
- package/dist/analyzers/security/aggregator.js +8 -48
- package/dist/analyzers/security/aggregator.js.map +1 -1
- package/dist/analyzers/security/gather.d.ts +4 -3
- package/dist/analyzers/security/gather.d.ts.map +1 -1
- package/dist/analyzers/security/gather.js +23 -5
- package/dist/analyzers/security/gather.js.map +1 -1
- package/dist/analyzers/security/index.d.ts +1 -1
- package/dist/analyzers/security/index.js +2 -2
- package/dist/analyzers/security/index.js.map +1 -1
- package/dist/analyzers/tools/autogen-header.js +1 -1
- package/dist/analyzers/tools/cloc.js +3 -3
- package/dist/analyzers/tools/cloc.js.map +1 -1
- package/dist/analyzers/tools/deadline.d.ts +67 -0
- package/dist/analyzers/tools/deadline.d.ts.map +1 -0
- package/dist/analyzers/tools/deadline.js +81 -0
- package/dist/analyzers/tools/deadline.js.map +1 -0
- package/dist/analyzers/tools/exclusions.d.ts +6 -6
- package/dist/analyzers/tools/exclusions.js +6 -6
- package/dist/analyzers/tools/fingerprint.d.ts +91 -26
- package/dist/analyzers/tools/fingerprint.d.ts.map +1 -1
- package/dist/analyzers/tools/fingerprint.js +111 -22
- package/dist/analyzers/tools/fingerprint.js.map +1 -1
- package/dist/analyzers/tools/generic.d.ts.map +1 -1
- package/dist/analyzers/tools/generic.js +7 -2
- package/dist/analyzers/tools/generic.js.map +1 -1
- package/dist/analyzers/tools/gitleaks.d.ts +24 -1
- package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
- package/dist/analyzers/tools/gitleaks.js +21 -12
- package/dist/analyzers/tools/gitleaks.js.map +1 -1
- package/dist/analyzers/tools/graphify.js +1 -1
- package/dist/analyzers/tools/jscpd.js +1 -1
- package/dist/analyzers/tools/jscpd.js.map +1 -1
- package/dist/analyzers/tools/lint-label.d.ts +29 -0
- package/dist/analyzers/tools/lint-label.d.ts.map +1 -0
- package/dist/analyzers/tools/lint-label.js +23 -0
- package/dist/analyzers/tools/lint-label.js.map +1 -0
- package/dist/analyzers/tools/nuget-package-reference.d.ts +6 -4
- package/dist/analyzers/tools/nuget-package-reference.d.ts.map +1 -1
- package/dist/analyzers/tools/nuget-package-reference.js +7 -5
- package/dist/analyzers/tools/nuget-package-reference.js.map +1 -1
- package/dist/analyzers/tools/report-date.d.ts +17 -0
- package/dist/analyzers/tools/report-date.d.ts.map +1 -0
- package/dist/analyzers/tools/report-date.js +26 -0
- package/dist/analyzers/tools/report-date.js.map +1 -0
- package/dist/analyzers/tools/runner.js +3 -3
- package/dist/analyzers/tools/runner.js.map +1 -1
- package/dist/analyzers/tools/vendored-advisor.js +1 -1
- package/dist/analyzers/tools/walk-paths.d.ts +1 -1
- package/dist/analyzers/tools/walk-paths.js +1 -1
- package/dist/analyzers/tools/walk-source-files.js +1 -1
- package/dist/analyzers/types.d.ts +6 -4
- package/dist/analyzers/types.d.ts.map +1 -1
- package/dist/baseline/baseline-file.d.ts +104 -0
- package/dist/baseline/baseline-file.d.ts.map +1 -0
- package/dist/baseline/baseline-file.js +110 -0
- package/dist/baseline/baseline-file.js.map +1 -0
- package/dist/baseline/check-renderers.d.ts +108 -0
- package/dist/baseline/check-renderers.d.ts.map +1 -0
- package/dist/baseline/check-renderers.js +379 -0
- package/dist/baseline/check-renderers.js.map +1 -0
- package/dist/baseline/check.d.ts +127 -0
- package/dist/baseline/check.d.ts.map +1 -0
- package/dist/baseline/check.js +462 -0
- package/dist/baseline/check.js.map +1 -0
- package/dist/baseline/content-hash.d.ts +83 -0
- package/dist/baseline/content-hash.d.ts.map +1 -0
- package/dist/baseline/content-hash.js +131 -0
- package/dist/baseline/content-hash.js.map +1 -0
- package/dist/baseline/create.d.ts +96 -0
- package/dist/baseline/create.d.ts.map +1 -0
- package/dist/baseline/create.js +339 -0
- package/dist/baseline/create.js.map +1 -0
- package/dist/baseline/entry-to-located.d.ts +35 -0
- package/dist/baseline/entry-to-located.d.ts.map +1 -0
- package/dist/baseline/entry-to-located.js +72 -0
- package/dist/baseline/entry-to-located.js.map +1 -0
- package/dist/baseline/finding-identity.d.ts +47 -0
- package/dist/baseline/finding-identity.d.ts.map +1 -0
- package/dist/baseline/finding-identity.js +292 -0
- package/dist/baseline/finding-identity.js.map +1 -0
- package/dist/baseline/git-aware-match.d.ts +146 -0
- package/dist/baseline/git-aware-match.d.ts.map +1 -0
- package/dist/baseline/git-aware-match.js +439 -0
- package/dist/baseline/git-aware-match.js.map +1 -0
- package/dist/baseline/policy.d.ts +171 -0
- package/dist/baseline/policy.d.ts.map +1 -0
- package/dist/baseline/policy.js +206 -0
- package/dist/baseline/policy.js.map +1 -0
- package/dist/baseline/producers/health.d.ts +30 -0
- package/dist/baseline/producers/health.d.ts.map +1 -0
- package/dist/baseline/producers/health.js +42 -0
- package/dist/baseline/producers/health.js.map +1 -0
- package/dist/baseline/producers/index.d.ts +164 -0
- package/dist/baseline/producers/index.d.ts.map +1 -0
- package/dist/baseline/producers/index.js +200 -0
- package/dist/baseline/producers/index.js.map +1 -0
- package/dist/baseline/producers/licenses.d.ts +23 -0
- package/dist/baseline/producers/licenses.d.ts.map +1 -0
- package/dist/baseline/producers/licenses.js +46 -0
- package/dist/baseline/producers/licenses.js.map +1 -0
- package/dist/baseline/producers/quality.d.ts +39 -0
- package/dist/baseline/producers/quality.d.ts.map +1 -0
- package/dist/baseline/producers/quality.js +84 -0
- package/dist/baseline/producers/quality.js.map +1 -0
- package/dist/baseline/producers/secret-hmac.d.ts +45 -0
- package/dist/baseline/producers/secret-hmac.d.ts.map +1 -0
- package/dist/baseline/producers/secret-hmac.js +70 -0
- package/dist/baseline/producers/secret-hmac.js.map +1 -0
- package/dist/baseline/producers/security.d.ts +59 -0
- package/dist/baseline/producers/security.d.ts.map +1 -0
- package/dist/baseline/producers/security.js +135 -0
- package/dist/baseline/producers/security.js.map +1 -0
- package/dist/baseline/producers/tests.d.ts +36 -0
- package/dist/baseline/producers/tests.d.ts.map +1 -0
- package/dist/baseline/producers/tests.js +69 -0
- package/dist/baseline/producers/tests.js.map +1 -0
- package/dist/baseline/salt.d.ts +45 -0
- package/dist/baseline/salt.d.ts.map +1 -0
- package/dist/baseline/salt.js +113 -0
- package/dist/baseline/salt.js.map +1 -0
- package/dist/baseline/show.d.ts +79 -0
- package/dist/baseline/show.d.ts.map +1 -0
- package/dist/baseline/show.js +233 -0
- package/dist/baseline/show.js.map +1 -0
- package/dist/baseline/types.d.ts +482 -0
- package/dist/baseline/types.d.ts.map +1 -0
- package/dist/baseline/types.js +53 -0
- package/dist/baseline/types.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +395 -92
- package/dist/cli.js.map +1 -1
- package/dist/codebase-scanner.d.ts.map +1 -1
- package/dist/codebase-scanner.js +0 -1
- package/dist/codebase-scanner.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -4
- package/dist/constants.js.map +1 -1
- package/dist/detect.js +3 -3
- package/dist/detect.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +22 -25
- package/dist/doctor.js.map +1 -1
- package/dist/fail-on.d.ts +84 -0
- package/dist/fail-on.d.ts.map +1 -0
- package/dist/fail-on.js +128 -0
- package/dist/fail-on.js.map +1 -0
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +2 -141
- package/dist/generator.js.map +1 -1
- package/dist/languages/capabilities/provider.d.ts +4 -4
- package/dist/languages/capabilities/types.d.ts +1 -1
- package/dist/languages/csharp.d.ts.map +1 -1
- package/dist/languages/csharp.js +15 -24
- package/dist/languages/csharp.js.map +1 -1
- package/dist/languages/go.d.ts.map +1 -1
- package/dist/languages/go.js +0 -15
- package/dist/languages/go.js.map +1 -1
- package/dist/languages/index.d.ts +4 -3
- package/dist/languages/index.d.ts.map +1 -1
- package/dist/languages/index.js +3 -2
- package/dist/languages/index.js.map +1 -1
- package/dist/languages/java.d.ts.map +1 -1
- package/dist/languages/java.js +0 -6
- package/dist/languages/java.js.map +1 -1
- package/dist/languages/kotlin.d.ts.map +1 -1
- package/dist/languages/kotlin.js +0 -11
- package/dist/languages/kotlin.js.map +1 -1
- package/dist/languages/python.d.ts.map +1 -1
- package/dist/languages/python.js +0 -15
- package/dist/languages/python.js.map +1 -1
- package/dist/languages/ruby.d.ts.map +1 -1
- package/dist/languages/ruby.js +0 -6
- package/dist/languages/ruby.js.map +1 -1
- package/dist/languages/rust.d.ts.map +1 -1
- package/dist/languages/rust.js +0 -4
- package/dist/languages/rust.js.map +1 -1
- package/dist/languages/types.d.ts +9 -35
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript.d.ts.map +1 -1
- package/dist/languages/typescript.js +26 -4
- package/dist/languages/typescript.js.map +1 -1
- package/dist/lib.d.ts +2 -3
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +3 -6
- package/dist/lib.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +0 -10
- package/dist/prompts.js.map +1 -1
- package/dist/report-schema.d.ts +42 -0
- package/dist/report-schema.d.ts.map +1 -0
- package/dist/report-schema.js +54 -0
- package/dist/report-schema.js.map +1 -0
- package/dist/ship-installers.d.ts +106 -0
- package/dist/ship-installers.d.ts.map +1 -0
- package/dist/ship-installers.js +415 -0
- package/dist/ship-installers.js.map +1 -0
- package/dist/types.d.ts +0 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +0 -4
- package/dist/update.js.map +1 -1
- package/package.json +17 -11
- package/templates/.claude/agents/onboarding.md +5 -4
- package/templates/.claude/agents-available/codebase-explorer.md +1 -1
- package/templates/.claude/agents-available/debugger.md +2 -2
- package/templates/.claude/agents-available/health-auditor.md +2 -2
- package/templates/.claude/commands/doctor.md +20 -12
- package/templates/.claude/skills/build/SKILL.md.template +22 -30
- package/templates/.claude/skills/deploy/SKILL.md.template +5 -25
- package/templates/.claude/skills/doctor/SKILL.md +24 -47
- package/templates/.claude/skills/gcloud/SKILL.md +5 -5
- package/templates/.claude/skills/learned/SKILL.md +1 -1
- package/templates/.claude/skills/pulumi/SKILL.md +2 -2
- package/templates/.claude/skills/quality/SKILL.md.template +4 -23
- package/templates/.claude/skills/review/SKILL.md.template +4 -3
- package/templates/.claude/skills/scaffold/SKILL.md.template +5 -15
- package/templates/.claude/skills/secrets/SKILL.md +20 -21
- package/templates/.claude/skills/session/SKILL.md +20 -31
- package/templates/.claude/skills/test/SKILL.md.template +1 -7
- package/templates/.devcontainer/devcontainer.json +81 -0
- package/templates/.devcontainer/install-agent-clis.sh +42 -0
- package/templates/.devcontainer/post-create.sh +67 -0
- package/templates/.githooks/pre-commit +55 -0
- package/templates/.githooks/pre-push +63 -0
- package/templates/.github/workflows/dxkit-baseline-refresh.yml +78 -0
- package/templates/.github/workflows/dxkit-guardrails.yml +98 -0
- package/templates/CLAUDE.md.template +62 -196
- package/dist/project-yaml.d.ts +0 -13
- package/dist/project-yaml.d.ts.map +0 -1
- package/dist/project-yaml.js +0 -188
- package/dist/project-yaml.js.map +0 -1
- package/templates/.ai/README.md +0 -117
- package/templates/.ai/prompts/execution-prompt.md +0 -9
- package/templates/.ai/prompts/planning-prompt.md +0 -18
- package/templates/.ai/prompts/session-end-template.md +0 -182
- package/templates/.ai/prompts/session-end.md +0 -132
- package/templates/.ai/prompts/session-start.md +0 -109
- package/templates/.ai/prompts/step-by-step.md +0 -113
- package/templates/.ai/sessions/.gitkeep +0 -0
- package/templates/.claude/commands/setup-pr-review.md +0 -72
- package/templates/.devcontainer/Dockerfile.dev.template +0 -89
- package/templates/.devcontainer/devcontainer.json.template +0 -184
- package/templates/.devcontainer/docker-compose.yml.template +0 -105
- package/templates/.devcontainer/init-scripts/01-init.sql.template +0 -12
- package/templates/.devcontainer/post-create.sh.template +0 -298
- package/templates/.github/workflows/ci.yml.template +0 -399
- package/templates/.github/workflows/quality.yml.template +0 -376
- package/templates/.pre-commit-config.yaml.template +0 -106
- package/templates/.project/config/edit_config.py +0 -275
- package/templates/.project/config/project_config.py +0 -894
- package/templates/.project/scripts/codegen/generate-all.sh +0 -20
- package/templates/.project/scripts/codegen/validate-all.sh +0 -17
- package/templates/.project/scripts/docs/generate-all.sh +0 -30
- package/templates/.project/scripts/docs/serve.sh +0 -20
- package/templates/.project/scripts/quality/fix-all.sh +0 -138
- package/templates/.project/scripts/quality/lint-go.sh +0 -34
- package/templates/.project/scripts/quality/lint-python.sh +0 -54
- package/templates/.project/scripts/quality/run-all.sh +0 -497
- package/templates/.project/scripts/session/commit.sh +0 -70
- package/templates/.project/scripts/session/create-pr.sh +0 -165
- package/templates/.project/scripts/session/end.sh +0 -207
- package/templates/.project/scripts/session/start.sh +0 -233
- package/templates/.project/scripts/setup/doctor.sh +0 -404
- package/templates/.project/scripts/setup/interactive-setup.sh +0 -585
- package/templates/.project/scripts/sync/sync-template.sh +0 -328
- package/templates/.project/scripts/test/run-all.sh +0 -179
- package/templates/.project/scripts/test/run-quick.sh +0 -25
- package/templates/Makefile +0 -514
- package/templates/config/versions.yaml +0 -57
- package/templates/configs/go/.golangci.yml.template +0 -172
- package/templates/configs/go/go.mod.template +0 -15
- package/templates/configs/java/README.md +0 -6
- package/templates/configs/kotlin/README.md +0 -6
- package/templates/configs/node/package.json.template +0 -67
- package/templates/configs/node/tsconfig.json.template +0 -53
- package/templates/configs/python/pyproject.toml.template +0 -92
- package/templates/configs/python/pytest.ini.template +0 -64
- package/templates/configs/python/ruff.toml.template +0 -79
- package/templates/configs/ruby/README.md +0 -6
- package/templates/configs/rust/Cargo.toml.template +0 -51
- package/templates/configs/shared/.editorconfig +0 -67
- package/templates/scripts/validate-templates.sh +0 -449
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Brownfield policy + status classifier.
|
|
4
|
+
*
|
|
5
|
+
* The matcher in `git-aware-match.ts` emits raw `MatchPair`s with one
|
|
6
|
+
* of four statuses (persisted / relocated / added / removed) plus a
|
|
7
|
+
* confidence score and structured reasons. The guardrail check needs
|
|
8
|
+
* a richer taxonomy — the difference between "developer introduced
|
|
9
|
+
* a new finding" and "a scanner update surfaced a finding that was
|
|
10
|
+
* always there" matters enormously for whether to block a PR.
|
|
11
|
+
*
|
|
12
|
+
* This module is the bridge. It takes a `MatchPair` plus optional
|
|
13
|
+
* context (severity, scanner-version diff, config diff) and a
|
|
14
|
+
* `BrownfieldPolicy`, then emits a `ClassifyResult` carrying the
|
|
15
|
+
* post-policy `FindingStatus`, the block/warn verdict, and the
|
|
16
|
+
* composed reason chain.
|
|
17
|
+
*
|
|
18
|
+
* Pure module — no I/O, deterministic over its inputs.
|
|
19
|
+
*
|
|
20
|
+
* Producer wiring note: today's classifier emits a subset of the full
|
|
21
|
+
* `FindingStatus` taxonomy. Reservations for `probable_existing`,
|
|
22
|
+
* `newly_detected`, and `fixed` are declared in the type space so
|
|
23
|
+
* Phase 3's baseline-metadata work can light them up incrementally
|
|
24
|
+
* without re-shaping consumer code.
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.DEFAULT_BROWNFIELD_POLICY = void 0;
|
|
28
|
+
exports.classify = classify;
|
|
29
|
+
exports.classifyAll = classifyAll;
|
|
30
|
+
/**
|
|
31
|
+
* Default brownfield policy. Captures the conservative posture from
|
|
32
|
+
* the agentic-brownfield strategy: block only on high-confidence new
|
|
33
|
+
* regressions; warn on the categories that suggest a problem might
|
|
34
|
+
* be real but might also be drift; legacy debt is permitted.
|
|
35
|
+
*
|
|
36
|
+
* Confidence thresholds: secrets + critical security demand a tight
|
|
37
|
+
* confidence threshold (a low-confidence persisted secret pairing
|
|
38
|
+
* gets demoted to uncertain and warned, not blocked). Lower-severity
|
|
39
|
+
* findings can pair on weaker signal because the cost of a false
|
|
40
|
+
* "secret is new" event is much higher than a false "TODO is new."
|
|
41
|
+
*/
|
|
42
|
+
exports.DEFAULT_BROWNFIELD_POLICY = Object.freeze({
|
|
43
|
+
mode: 'brownfield',
|
|
44
|
+
block: Object.freeze(['added']),
|
|
45
|
+
warn: Object.freeze([
|
|
46
|
+
'probable_existing',
|
|
47
|
+
'newly_detected',
|
|
48
|
+
'tooling_drift',
|
|
49
|
+
'config_drift',
|
|
50
|
+
'uncertain',
|
|
51
|
+
]),
|
|
52
|
+
confidence: Object.freeze({
|
|
53
|
+
critical: 0.75,
|
|
54
|
+
high: 0.8,
|
|
55
|
+
medium: 0.85,
|
|
56
|
+
low: 0.9,
|
|
57
|
+
}),
|
|
58
|
+
blockRules: Object.freeze({
|
|
59
|
+
newSecret: true,
|
|
60
|
+
newCriticalSecurity: true,
|
|
61
|
+
newHighSecurity: true,
|
|
62
|
+
newCriticalDependencyVulnerability: true,
|
|
63
|
+
newHighReachableDependencyVulnerability: true,
|
|
64
|
+
newUntestedChangedSource: true,
|
|
65
|
+
newSevereQualityIssueInChangedFiles: true,
|
|
66
|
+
}),
|
|
67
|
+
addedRequiresChangedLines: Object.freeze(['code', 'hygiene']),
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Classify one match pair against a brownfield policy.
|
|
71
|
+
*
|
|
72
|
+
* Pipeline:
|
|
73
|
+
* 1. Start with the matcher's `pair.status` as the candidate
|
|
74
|
+
* `FindingStatus`.
|
|
75
|
+
* 2. For `added`: check drift context. Scanner-version drift wins
|
|
76
|
+
* (more specific signal) over config drift; both demote to
|
|
77
|
+
* drift-bucket statuses regardless of severity.
|
|
78
|
+
* 3. For `persisted` / `relocated`: check confidence against the
|
|
79
|
+
* per-severity threshold. Below threshold demotes to
|
|
80
|
+
* `'uncertain'`.
|
|
81
|
+
* 4. Apply block-rule overrides: if a block-rule fires for this
|
|
82
|
+
* kind+severity combination AND the candidate status is
|
|
83
|
+
* `'added'`, the result blocks even if `'added'` weren't in the
|
|
84
|
+
* policy's block list.
|
|
85
|
+
* 5. Apply the policy's `block` / `warn` membership to the final
|
|
86
|
+
* status to produce the booleans.
|
|
87
|
+
*/
|
|
88
|
+
function classify(pair, policy = exports.DEFAULT_BROWNFIELD_POLICY, context = {}) {
|
|
89
|
+
let status = pair.status;
|
|
90
|
+
const reasons = [...pair.reasons];
|
|
91
|
+
// Step 2: drift context can reclassify 'added'.
|
|
92
|
+
if (status === 'added') {
|
|
93
|
+
if (context.scannerVersionDiffers) {
|
|
94
|
+
status = 'tooling_drift';
|
|
95
|
+
reasons.push({
|
|
96
|
+
code: 'tooling-drift',
|
|
97
|
+
detail: 'scanner or advisory-db version changed between runs',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else if (context.configDiffers) {
|
|
101
|
+
status = 'config_drift';
|
|
102
|
+
reasons.push({
|
|
103
|
+
code: 'config-drift',
|
|
104
|
+
detail: 'suppression or policy config changed between runs',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
else if (context.kind &&
|
|
108
|
+
policy.addedRequiresChangedLines.includes(context.kind) &&
|
|
109
|
+
context.overlapsChangedLines === false) {
|
|
110
|
+
// Scanner-wobble demotion: an `added` finding from a high-
|
|
111
|
+
// wobble scanner (semgrep code, grep-based hygiene) that
|
|
112
|
+
// sits outside the diff's changed lines is more likely a
|
|
113
|
+
// baseline gap than a real regression. Demote to `uncertain`
|
|
114
|
+
// (warn). The block-rules below still fire for findings the
|
|
115
|
+
// diff actually touched.
|
|
116
|
+
status = 'uncertain';
|
|
117
|
+
reasons.push({
|
|
118
|
+
code: 'unchanged-lines',
|
|
119
|
+
detail: `${context.kind} finding outside diff hunks — demoted from added to uncertain (likely scanner wobble, not a developer-introduced regression)`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Step 3: confidence demotion for persisted/relocated pairs.
|
|
124
|
+
if (status === 'persisted' || status === 'relocated') {
|
|
125
|
+
const threshold = context.severity
|
|
126
|
+
? policy.confidence[context.severity]
|
|
127
|
+
: Math.min(...Object.values(policy.confidence));
|
|
128
|
+
if (pair.confidence < threshold) {
|
|
129
|
+
reasons.push({
|
|
130
|
+
code: 'low-confidence',
|
|
131
|
+
detail: `match confidence ${pair.confidence.toFixed(2)} below threshold ${threshold.toFixed(2)}` +
|
|
132
|
+
(context.severity ? ` for severity ${context.severity}` : ''),
|
|
133
|
+
});
|
|
134
|
+
status = 'uncertain';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Step 4: block-rule overrides for newly-added findings.
|
|
138
|
+
const blockRuleHit = evaluateBlockRules(status, policy.blockRules, context);
|
|
139
|
+
if (blockRuleHit) {
|
|
140
|
+
reasons.push({
|
|
141
|
+
code: 'block-rule',
|
|
142
|
+
detail: `policy block-rule fired: ${blockRuleHit}`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
// Step 5: policy block/warn membership.
|
|
146
|
+
const blocks = blockRuleHit !== null || policy.block.includes(status);
|
|
147
|
+
const warns = policy.warn.includes(status);
|
|
148
|
+
return { status, blocks, warns, reasons };
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check whether any block-rule fires for the given classified pair.
|
|
152
|
+
* Returns the matching rule's name (for reason rendering) or null
|
|
153
|
+
* when no rule fires.
|
|
154
|
+
*
|
|
155
|
+
* Block-rules only apply to `added` status — they exist to escalate
|
|
156
|
+
* specific kinds of new findings beyond the generic policy. A
|
|
157
|
+
* `tooling_drift` reclassification means the `added` status is gone
|
|
158
|
+
* and the block-rule no longer applies.
|
|
159
|
+
*/
|
|
160
|
+
function evaluateBlockRules(status, rules, context) {
|
|
161
|
+
if (status !== 'added')
|
|
162
|
+
return null;
|
|
163
|
+
if (rules.newSecret && context.kind === 'secret')
|
|
164
|
+
return 'newSecret';
|
|
165
|
+
if (rules.newCriticalSecurity && context.kind === 'code' && context.severity === 'critical') {
|
|
166
|
+
return 'newCriticalSecurity';
|
|
167
|
+
}
|
|
168
|
+
if (rules.newHighSecurity && context.kind === 'code' && context.severity === 'high') {
|
|
169
|
+
return 'newHighSecurity';
|
|
170
|
+
}
|
|
171
|
+
if (rules.newCriticalDependencyVulnerability &&
|
|
172
|
+
context.kind === 'dep-vuln' &&
|
|
173
|
+
context.severity === 'critical') {
|
|
174
|
+
return 'newCriticalDependencyVulnerability';
|
|
175
|
+
}
|
|
176
|
+
if (rules.newHighReachableDependencyVulnerability &&
|
|
177
|
+
context.kind === 'dep-vuln' &&
|
|
178
|
+
context.severity === 'high' &&
|
|
179
|
+
context.reachable === true) {
|
|
180
|
+
return 'newHighReachableDependencyVulnerability';
|
|
181
|
+
}
|
|
182
|
+
if (rules.newUntestedChangedSource &&
|
|
183
|
+
context.kind === 'test-gap' &&
|
|
184
|
+
context.overlapsChangedLines === true) {
|
|
185
|
+
return 'newUntestedChangedSource';
|
|
186
|
+
}
|
|
187
|
+
if (rules.newSevereQualityIssueInChangedFiles &&
|
|
188
|
+
(context.kind === 'code' || context.kind === 'hygiene') &&
|
|
189
|
+
(context.severity === 'critical' || context.severity === 'high') &&
|
|
190
|
+
context.overlapsChangedLines === true) {
|
|
191
|
+
return 'newSevereQualityIssueInChangedFiles';
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Convenience: classify every pair in a match result against the
|
|
197
|
+
* same policy. Returns an array aligned with the input pair order
|
|
198
|
+
* so callers can render side-by-side. Per-pair context (severity,
|
|
199
|
+
* kind, drift flags) is supplied via the optional `contextFor`
|
|
200
|
+
* callback — callers map their `FindingId` back to the producer
|
|
201
|
+
* envelope to fill in the fields the classifier reads.
|
|
202
|
+
*/
|
|
203
|
+
function classifyAll(pairs, policy = exports.DEFAULT_BROWNFIELD_POLICY, contextFor = () => ({})) {
|
|
204
|
+
return pairs.map((pair) => classify(pair, policy, contextFor(pair)));
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/baseline/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health → baseline-entry producer.
|
|
3
|
+
*
|
|
4
|
+
* One kind today: `large-file` — source files whose line count
|
|
5
|
+
* exceeds the canonical large-file threshold (500 lines). Identity
|
|
6
|
+
* is per-file: the binary "this file is over the threshold" signal
|
|
7
|
+
* is what guardrails act on. Crossing back under the threshold
|
|
8
|
+
* removes the identity; crossing back over re-adds it.
|
|
9
|
+
*
|
|
10
|
+
* Producer reads from `HealthMetrics.largestFiles`, which is already
|
|
11
|
+
* an `Array<{ path, lines }>` produced by the canonical generic-
|
|
12
|
+
* metrics gather. The 500-line threshold matches the
|
|
13
|
+
* `filesOver500Lines` aggregate the same gather emits — keeping the
|
|
14
|
+
* two in sync ensures the per-file identity set sums to the
|
|
15
|
+
* aggregate count.
|
|
16
|
+
*/
|
|
17
|
+
import type { BaselineEntry } from '../types';
|
|
18
|
+
import type { HealthMetrics } from '../../analyzers/types';
|
|
19
|
+
/** Canonical large-file threshold — file is "too large" at strictly
|
|
20
|
+
* more than this many lines. Mirror of the constant the generic-
|
|
21
|
+
* metrics gather already uses; documented as part of the file-size
|
|
22
|
+
* signal in the CLAUDE.md maintainability surface. */
|
|
23
|
+
export declare const LARGE_FILE_THRESHOLD_LINES = 500;
|
|
24
|
+
/**
|
|
25
|
+
* Build `large-file` entries from the canonical `HealthMetrics`.
|
|
26
|
+
* Files with `lines <= threshold` are skipped so the identity set
|
|
27
|
+
* matches the user-facing aggregate count.
|
|
28
|
+
*/
|
|
29
|
+
export declare function largeFilesToBaselineEntries(metrics: HealthMetrics): BaselineEntry[];
|
|
30
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../src/baseline/producers/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,aAAa,EAA0B,MAAM,UAAU,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;uDAGuD;AACvD,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,EAAE,CAQnF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Health → baseline-entry producer.
|
|
4
|
+
*
|
|
5
|
+
* One kind today: `large-file` — source files whose line count
|
|
6
|
+
* exceeds the canonical large-file threshold (500 lines). Identity
|
|
7
|
+
* is per-file: the binary "this file is over the threshold" signal
|
|
8
|
+
* is what guardrails act on. Crossing back under the threshold
|
|
9
|
+
* removes the identity; crossing back over re-adds it.
|
|
10
|
+
*
|
|
11
|
+
* Producer reads from `HealthMetrics.largestFiles`, which is already
|
|
12
|
+
* an `Array<{ path, lines }>` produced by the canonical generic-
|
|
13
|
+
* metrics gather. The 500-line threshold matches the
|
|
14
|
+
* `filesOver500Lines` aggregate the same gather emits — keeping the
|
|
15
|
+
* two in sync ensures the per-file identity set sums to the
|
|
16
|
+
* aggregate count.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.LARGE_FILE_THRESHOLD_LINES = void 0;
|
|
20
|
+
exports.largeFilesToBaselineEntries = largeFilesToBaselineEntries;
|
|
21
|
+
const finding_identity_1 = require("../finding-identity");
|
|
22
|
+
/** Canonical large-file threshold — file is "too large" at strictly
|
|
23
|
+
* more than this many lines. Mirror of the constant the generic-
|
|
24
|
+
* metrics gather already uses; documented as part of the file-size
|
|
25
|
+
* signal in the CLAUDE.md maintainability surface. */
|
|
26
|
+
exports.LARGE_FILE_THRESHOLD_LINES = 500;
|
|
27
|
+
/**
|
|
28
|
+
* Build `large-file` entries from the canonical `HealthMetrics`.
|
|
29
|
+
* Files with `lines <= threshold` are skipped so the identity set
|
|
30
|
+
* matches the user-facing aggregate count.
|
|
31
|
+
*/
|
|
32
|
+
function largeFilesToBaselineEntries(metrics) {
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const f of metrics.largestFiles) {
|
|
35
|
+
if (f.lines <= exports.LARGE_FILE_THRESHOLD_LINES)
|
|
36
|
+
continue;
|
|
37
|
+
const input = { kind: 'large-file', file: f.path };
|
|
38
|
+
out.push({ id: (0, finding_identity_1.identityFor)(input), kind: 'large-file', file: f.path });
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/baseline/producers/health.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAiBH,kEAQC;AAvBD,0DAAkD;AAIlD;;;uDAGuD;AAC1C,QAAA,0BAA0B,GAAG,GAAG,CAAC;AAE9C;;;;GAIG;AACH,SAAgB,2BAA2B,CAAC,OAAsB;IAChE,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACrC,IAAI,CAAC,CAAC,KAAK,IAAI,kCAA0B;YAAE,SAAS;QACpD,MAAM,KAAK,GAA2B,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3E,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAA,8BAAW,EAAC,KAAK,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Producer registry — the single canonical home for everything that
|
|
3
|
+
* turns analyzer output into `BaselineEntry`s.
|
|
4
|
+
*
|
|
5
|
+
* # Why this exists (CLAUDE.md Rule 10)
|
|
6
|
+
*
|
|
7
|
+
* The baseline file is the durable contract the guardrail check
|
|
8
|
+
* reads. Every analyzer that surfaces per-finding output MUST flow
|
|
9
|
+
* through a registered producer so guardrails don't silently miss
|
|
10
|
+
* its findings. Without the registry, adding a new analyzer means
|
|
11
|
+
* remembering to also edit `create.ts` orchestration — easy to
|
|
12
|
+
* forget, and the bug is invisible (the guardrail check passes even
|
|
13
|
+
* when a new finding kind is silently bypassed).
|
|
14
|
+
*
|
|
15
|
+
* With the registry:
|
|
16
|
+
* - Adding a new analyzer is a one-line `PRODUCERS.push(...)`.
|
|
17
|
+
* - The orchestrator iterates the registry — no per-producer
|
|
18
|
+
* `findings.push(...)` calls to forget.
|
|
19
|
+
* - A contract test asserts every `IdentityInput` discriminant
|
|
20
|
+
* kind is either contributed by a registered producer OR
|
|
21
|
+
* listed in `DEFERRED_KINDS` with explicit rationale.
|
|
22
|
+
* - A synthetic-producer playbook test asserts the orchestrator
|
|
23
|
+
* stays registry-driven (adding a fake producer to the
|
|
24
|
+
* registry makes its entries appear in the baseline file
|
|
25
|
+
* without any edits to the orchestrator).
|
|
26
|
+
*
|
|
27
|
+
* # Producer contract
|
|
28
|
+
*
|
|
29
|
+
* Each producer:
|
|
30
|
+
* 1. Declares the identity kinds it contributes via `contributes`.
|
|
31
|
+
* 2. Reads from the shared `ProducerContext` (gathered once by
|
|
32
|
+
* the orchestrator so multiple producers don't re-shell the
|
|
33
|
+
* same analyzer).
|
|
34
|
+
* 3. Returns `BaselineEntry[]` — pure or near-pure, depending on
|
|
35
|
+
* whether content-hash stamping is needed.
|
|
36
|
+
*
|
|
37
|
+
* # Adding a new identity kind
|
|
38
|
+
*
|
|
39
|
+
* 1. Add the discriminant to `IdentityInput` in `types.ts`.
|
|
40
|
+
* 2. Add the case branch in `identityFor`.
|
|
41
|
+
* 3. EITHER add a new producer here (or extend an existing one)
|
|
42
|
+
* so `contributes` covers the new kind, OR add the kind to
|
|
43
|
+
* `DEFERRED_KINDS` with rationale + landing phase.
|
|
44
|
+
* 4. Add a fixture row in `test/baseline/finding-identity.test.ts`
|
|
45
|
+
* (Rule 9 / per-kind fixture contract).
|
|
46
|
+
*
|
|
47
|
+
* The contract test enforces steps 3 + 4 at runtime; the
|
|
48
|
+
* exhaustive switch in `identityFor` enforces step 2 at compile
|
|
49
|
+
* time. The result: no new identity kind can land in a way that
|
|
50
|
+
* silently bypasses guardrails.
|
|
51
|
+
*/
|
|
52
|
+
import type { GitleaksRawSecret } from '../../analyzers/tools/gitleaks';
|
|
53
|
+
import type { AnalysisResult } from '../../analysis-result';
|
|
54
|
+
import type { TestGapsReport } from '../../analyzers/tests/types';
|
|
55
|
+
import type { BaselineEntry } from '../types';
|
|
56
|
+
/** Every discriminant value the `BaselineEntry` union takes. Mirror
|
|
57
|
+
* of `IdentityInput['kind']` — kept as a separate alias because the
|
|
58
|
+
* registry contract speaks in terms of stored entries, not the
|
|
59
|
+
* identity-compute input. */
|
|
60
|
+
export type IdentityKind = BaselineEntry['kind'];
|
|
61
|
+
/**
|
|
62
|
+
* Hygiene-marker counts + stale-file list returned by
|
|
63
|
+
* `gatherHygieneMarkers`. Replicated here as the producer-context
|
|
64
|
+
* field type so producers don't need to depend on the analyzer
|
|
65
|
+
* module's gather signature.
|
|
66
|
+
*/
|
|
67
|
+
export interface HygieneSnapshot {
|
|
68
|
+
readonly staleFiles: ReadonlyArray<string>;
|
|
69
|
+
readonly todoCount: number;
|
|
70
|
+
readonly fixmeCount: number;
|
|
71
|
+
readonly hackCount: number;
|
|
72
|
+
readonly consoleLogCount: number;
|
|
73
|
+
readonly mixedLanguages: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Per-run inputs every producer reads from. Gathered ONCE by the
|
|
77
|
+
* orchestrator; producers are pure (or content-hash-impure for
|
|
78
|
+
* stamping) over this context. Adding a new producer that needs a
|
|
79
|
+
* new analyzer means extending this context — a single, visible
|
|
80
|
+
* extension point.
|
|
81
|
+
*/
|
|
82
|
+
export interface ProducerContext {
|
|
83
|
+
/** Absolute repo path. */
|
|
84
|
+
readonly cwd: string;
|
|
85
|
+
/** Commit SHA the baseline anchors to. Empty string when not in
|
|
86
|
+
* a git repo — content-hash stamping is then disabled but other
|
|
87
|
+
* producers still emit normally. */
|
|
88
|
+
readonly commitSha: string;
|
|
89
|
+
/** Resolved repo salt (from `resolveSalt`). Threaded into
|
|
90
|
+
* producers that compute HMACs. */
|
|
91
|
+
readonly salt: string;
|
|
92
|
+
/** Canonical cached analysis envelope — capabilities + metrics
|
|
93
|
+
* + provenance for every gather pipeline. */
|
|
94
|
+
readonly analysisResult: AnalysisResult;
|
|
95
|
+
/** Test-gaps report (separate analyzer because the gap detection
|
|
96
|
+
* + import-graph reachability isn't part of the cached
|
|
97
|
+
* envelope). */
|
|
98
|
+
readonly testGapsReport: TestGapsReport;
|
|
99
|
+
/** Hygiene-marker snapshot — stale file list + aggregate counts. */
|
|
100
|
+
readonly hygiene: HygieneSnapshot;
|
|
101
|
+
/** Raw secrets gitleaks captured (process-only; never written to
|
|
102
|
+
* disk; consumed by the secret-HMAC producer). */
|
|
103
|
+
readonly rawSecrets: ReadonlyArray<GitleaksRawSecret>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The registry entry shape. A producer self-describes the kinds it
|
|
107
|
+
* contributes and supplies the function to produce them.
|
|
108
|
+
*/
|
|
109
|
+
export interface BaselineProducer {
|
|
110
|
+
/** Human-readable name; surfaces in logs + contract-test
|
|
111
|
+
* diagnostics ("producer X contributed N entries"). */
|
|
112
|
+
readonly name: string;
|
|
113
|
+
/** Identity kinds this producer wires. The contract test reads
|
|
114
|
+
* the union across every producer and asserts it covers every
|
|
115
|
+
* `IdentityKind` value not in `DEFERRED_KINDS`. */
|
|
116
|
+
readonly contributes: ReadonlyArray<IdentityKind>;
|
|
117
|
+
/** Build `BaselineEntry`s from the shared context. Producers
|
|
118
|
+
* emit ZERO entries when their upstream data is missing
|
|
119
|
+
* (analyzer didn't run, envelope absent, etc.) — never throw
|
|
120
|
+
* for missing inputs. */
|
|
121
|
+
readonly produce: (ctx: ProducerContext) => BaselineEntry[];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Identity kinds declared in `IdentityInput` but not yet wired by
|
|
125
|
+
* any producer. Each entry MUST carry a `reason` (what blocks the
|
|
126
|
+
* producer today) and `landingPhase` (when we intend to wire it).
|
|
127
|
+
* The contract test asserts:
|
|
128
|
+
*
|
|
129
|
+
* - Every kind appearing here is NOT contributed by any
|
|
130
|
+
* registered producer (no double-counting).
|
|
131
|
+
* - Every `IdentityKind` is either contributed OR in this map.
|
|
132
|
+
*
|
|
133
|
+
* Adding a new identity kind without wiring a producer requires
|
|
134
|
+
* adding an entry here — the deferral becomes architecturally
|
|
135
|
+
* explicit rather than silently invisible.
|
|
136
|
+
*/
|
|
137
|
+
export declare const DEFERRED_KINDS: Readonly<Record<string, {
|
|
138
|
+
readonly reason: string;
|
|
139
|
+
readonly landingPhase: string;
|
|
140
|
+
}>>;
|
|
141
|
+
/**
|
|
142
|
+
* The canonical producer list. Order is preserved in baseline-file
|
|
143
|
+
* output for deterministic diffs; adding a new producer appends
|
|
144
|
+
* here and updates the contract-test expectations.
|
|
145
|
+
*
|
|
146
|
+
* Mutable for the synthetic-producer playbook test: the test
|
|
147
|
+
* substitutes a wrapped registry rather than mutating PRODUCERS
|
|
148
|
+
* directly. Callers MUST treat this as immutable.
|
|
149
|
+
*/
|
|
150
|
+
export declare const PRODUCERS: ReadonlyArray<BaselineProducer>;
|
|
151
|
+
/**
|
|
152
|
+
* Run every producer in `producers` against the shared context and
|
|
153
|
+
* flatten the result. The orchestrator calls this with `PRODUCERS`
|
|
154
|
+
* for production use; the playbook test calls it with an extended
|
|
155
|
+
* list to verify synthetic producers flow through.
|
|
156
|
+
*/
|
|
157
|
+
export declare function runProducers(ctx: ProducerContext, producers?: ReadonlyArray<BaselineProducer>): BaselineEntry[];
|
|
158
|
+
/**
|
|
159
|
+
* Every kind currently contributed by some producer in `producers`.
|
|
160
|
+
* Convenience used by the contract test + by the orchestrator for
|
|
161
|
+
* logging "this run produced entries across N kinds."
|
|
162
|
+
*/
|
|
163
|
+
export declare function wiredKinds(producers?: ReadonlyArray<BaselineProducer>): ReadonlySet<IdentityKind>;
|
|
164
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/baseline/producers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQ9C;;;8BAG8B;AAC9B,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;yCAEqC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;wCACoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;kDAC8C;IAC9C,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;qBAEiB;IACjB,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC;uDACmD;IACnD,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;CACvD;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;4DACwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;wDAEoD;IACpD,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAClD;;;8BAG0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,aAAa,EAAE,CAAC;CAC7D;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,CACnC,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CA2B1E,CAAC;AAiEH;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,EAAE,aAAa,CAAC,gBAAgB,CAOpD,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,eAAe,EACpB,SAAS,GAAE,aAAa,CAAC,gBAAgB,CAAa,GACrD,aAAa,EAAE,CAMjB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,SAAS,GAAE,aAAa,CAAC,gBAAgB,CAAa,GACrD,WAAW,CAAC,YAAY,CAAC,CAI3B"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Producer registry — the single canonical home for everything that
|
|
4
|
+
* turns analyzer output into `BaselineEntry`s.
|
|
5
|
+
*
|
|
6
|
+
* # Why this exists (CLAUDE.md Rule 10)
|
|
7
|
+
*
|
|
8
|
+
* The baseline file is the durable contract the guardrail check
|
|
9
|
+
* reads. Every analyzer that surfaces per-finding output MUST flow
|
|
10
|
+
* through a registered producer so guardrails don't silently miss
|
|
11
|
+
* its findings. Without the registry, adding a new analyzer means
|
|
12
|
+
* remembering to also edit `create.ts` orchestration — easy to
|
|
13
|
+
* forget, and the bug is invisible (the guardrail check passes even
|
|
14
|
+
* when a new finding kind is silently bypassed).
|
|
15
|
+
*
|
|
16
|
+
* With the registry:
|
|
17
|
+
* - Adding a new analyzer is a one-line `PRODUCERS.push(...)`.
|
|
18
|
+
* - The orchestrator iterates the registry — no per-producer
|
|
19
|
+
* `findings.push(...)` calls to forget.
|
|
20
|
+
* - A contract test asserts every `IdentityInput` discriminant
|
|
21
|
+
* kind is either contributed by a registered producer OR
|
|
22
|
+
* listed in `DEFERRED_KINDS` with explicit rationale.
|
|
23
|
+
* - A synthetic-producer playbook test asserts the orchestrator
|
|
24
|
+
* stays registry-driven (adding a fake producer to the
|
|
25
|
+
* registry makes its entries appear in the baseline file
|
|
26
|
+
* without any edits to the orchestrator).
|
|
27
|
+
*
|
|
28
|
+
* # Producer contract
|
|
29
|
+
*
|
|
30
|
+
* Each producer:
|
|
31
|
+
* 1. Declares the identity kinds it contributes via `contributes`.
|
|
32
|
+
* 2. Reads from the shared `ProducerContext` (gathered once by
|
|
33
|
+
* the orchestrator so multiple producers don't re-shell the
|
|
34
|
+
* same analyzer).
|
|
35
|
+
* 3. Returns `BaselineEntry[]` — pure or near-pure, depending on
|
|
36
|
+
* whether content-hash stamping is needed.
|
|
37
|
+
*
|
|
38
|
+
* # Adding a new identity kind
|
|
39
|
+
*
|
|
40
|
+
* 1. Add the discriminant to `IdentityInput` in `types.ts`.
|
|
41
|
+
* 2. Add the case branch in `identityFor`.
|
|
42
|
+
* 3. EITHER add a new producer here (or extend an existing one)
|
|
43
|
+
* so `contributes` covers the new kind, OR add the kind to
|
|
44
|
+
* `DEFERRED_KINDS` with rationale + landing phase.
|
|
45
|
+
* 4. Add a fixture row in `test/baseline/finding-identity.test.ts`
|
|
46
|
+
* (Rule 9 / per-kind fixture contract).
|
|
47
|
+
*
|
|
48
|
+
* The contract test enforces steps 3 + 4 at runtime; the
|
|
49
|
+
* exhaustive switch in `identityFor` enforces step 2 at compile
|
|
50
|
+
* time. The result: no new identity kind can land in a way that
|
|
51
|
+
* silently bypasses guardrails.
|
|
52
|
+
*/
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.PRODUCERS = exports.DEFERRED_KINDS = void 0;
|
|
55
|
+
exports.runProducers = runProducers;
|
|
56
|
+
exports.wiredKinds = wiredKinds;
|
|
57
|
+
const health_1 = require("./health");
|
|
58
|
+
const licenses_1 = require("./licenses");
|
|
59
|
+
const quality_1 = require("./quality");
|
|
60
|
+
const secret_hmac_1 = require("./secret-hmac");
|
|
61
|
+
const security_1 = require("./security");
|
|
62
|
+
const tests_1 = require("./tests");
|
|
63
|
+
/**
|
|
64
|
+
* Identity kinds declared in `IdentityInput` but not yet wired by
|
|
65
|
+
* any producer. Each entry MUST carry a `reason` (what blocks the
|
|
66
|
+
* producer today) and `landingPhase` (when we intend to wire it).
|
|
67
|
+
* The contract test asserts:
|
|
68
|
+
*
|
|
69
|
+
* - Every kind appearing here is NOT contributed by any
|
|
70
|
+
* registered producer (no double-counting).
|
|
71
|
+
* - Every `IdentityKind` is either contributed OR in this map.
|
|
72
|
+
*
|
|
73
|
+
* Adding a new identity kind without wiring a producer requires
|
|
74
|
+
* adding an entry here — the deferral becomes architecturally
|
|
75
|
+
* explicit rather than silently invisible.
|
|
76
|
+
*/
|
|
77
|
+
exports.DEFERRED_KINDS = Object.freeze({
|
|
78
|
+
'god-file': {
|
|
79
|
+
reason: 'graphify Python script does not yet surface per-file complexity offenders; ' +
|
|
80
|
+
'QualityMetrics.topGodFiles is forward-declared but unpopulated. ' +
|
|
81
|
+
'Substitute: large-file (>500 lines) overlaps the same files ~80%+ of the time.',
|
|
82
|
+
landingPhase: '2.6 / Phase 10s.2 (graphify-symbols expansion)',
|
|
83
|
+
},
|
|
84
|
+
hygiene: {
|
|
85
|
+
reason: 'gatherHygieneMarkers emits aggregate counts, not per-occurrence positions; ' +
|
|
86
|
+
'extending to surface Array<{file, line, marker}> is a small gather refactor. ' +
|
|
87
|
+
'Substitute: aggregate counts feed the Quality dimension score; ' +
|
|
88
|
+
'newSevereQualityIssueInChangedFiles block rule catches high-severity overlap.',
|
|
89
|
+
landingPhase: 'Phase 5 (pre-launch polish)',
|
|
90
|
+
},
|
|
91
|
+
'coverage-gap': {
|
|
92
|
+
reason: 'per-pack coverage adapters do not yet surface uncovered symbol ranges. ' +
|
|
93
|
+
'Five of eight packs (typescript / java / kotlin / ruby / go) land in ' +
|
|
94
|
+
'Phase 3.5 inside 2.5; remaining three (python / csharp / rust) decided ' +
|
|
95
|
+
'mid-Phase-3.5 based on adapter complexity. ' +
|
|
96
|
+
'Substitute: test-gap covers file-level untested; new uncovered functions ' +
|
|
97
|
+
'inside an already-tested file remain invisible until Phase 3.5 lands.',
|
|
98
|
+
landingPhase: 'Phase 3.5 (5 packs) / 2.6 (remaining)',
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
// ─── Producer module wrappers ─────────────────────────────────────────────
|
|
102
|
+
// Each wraps a producer module's pure function with the registry's
|
|
103
|
+
// `BaselineProducer` shape. Kept in this file (rather than alongside
|
|
104
|
+
// each producer module) so the registry stays the single discovery
|
|
105
|
+
// surface — readers see every wired producer + every deferral in
|
|
106
|
+
// one place.
|
|
107
|
+
const SECURITY_PRODUCER = {
|
|
108
|
+
name: 'security',
|
|
109
|
+
contributes: ['secret', 'code', 'config', 'dep-vuln'],
|
|
110
|
+
produce(ctx) {
|
|
111
|
+
const aggregate = ctx.analysisResult.capabilities.securityAggregate;
|
|
112
|
+
if (!aggregate)
|
|
113
|
+
return [];
|
|
114
|
+
return (0, security_1.securityAggregateToBaselineEntries)(aggregate, {
|
|
115
|
+
cwd: ctx.cwd,
|
|
116
|
+
commitSha: ctx.commitSha || undefined,
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const SECRET_HMAC_PRODUCER = {
|
|
121
|
+
name: 'secret-hmac',
|
|
122
|
+
contributes: ['secret-hmac'],
|
|
123
|
+
produce(ctx) {
|
|
124
|
+
return (0, secret_hmac_1.rawSecretsToBaselineEntries)({ rawSecrets: ctx.rawSecrets, salt: ctx.salt });
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
const QUALITY_PRODUCER = {
|
|
128
|
+
name: 'quality',
|
|
129
|
+
contributes: ['duplication', 'stale-file'],
|
|
130
|
+
produce(ctx) {
|
|
131
|
+
return [
|
|
132
|
+
...(0, quality_1.duplicationToBaselineEntries)(ctx.analysisResult.capabilities.duplication),
|
|
133
|
+
...(0, quality_1.staleFilesToBaselineEntries)(ctx.hygiene.staleFiles),
|
|
134
|
+
];
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
const HEALTH_PRODUCER = {
|
|
138
|
+
name: 'health',
|
|
139
|
+
contributes: ['large-file'],
|
|
140
|
+
produce(ctx) {
|
|
141
|
+
return (0, health_1.largeFilesToBaselineEntries)(ctx.analysisResult.metrics);
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
const LICENSES_PRODUCER = {
|
|
145
|
+
name: 'licenses',
|
|
146
|
+
contributes: ['license'],
|
|
147
|
+
produce(ctx) {
|
|
148
|
+
return (0, licenses_1.licensesToBaselineEntries)(ctx.analysisResult.capabilities.licenses);
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
const TESTS_PRODUCER = {
|
|
152
|
+
name: 'tests',
|
|
153
|
+
contributes: ['test-gap', 'test-file-degradation'],
|
|
154
|
+
produce(ctx) {
|
|
155
|
+
return (0, tests_1.testGapsToBaselineEntries)(ctx.testGapsReport);
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* The canonical producer list. Order is preserved in baseline-file
|
|
160
|
+
* output for deterministic diffs; adding a new producer appends
|
|
161
|
+
* here and updates the contract-test expectations.
|
|
162
|
+
*
|
|
163
|
+
* Mutable for the synthetic-producer playbook test: the test
|
|
164
|
+
* substitutes a wrapped registry rather than mutating PRODUCERS
|
|
165
|
+
* directly. Callers MUST treat this as immutable.
|
|
166
|
+
*/
|
|
167
|
+
exports.PRODUCERS = Object.freeze([
|
|
168
|
+
SECURITY_PRODUCER,
|
|
169
|
+
SECRET_HMAC_PRODUCER,
|
|
170
|
+
QUALITY_PRODUCER,
|
|
171
|
+
HEALTH_PRODUCER,
|
|
172
|
+
LICENSES_PRODUCER,
|
|
173
|
+
TESTS_PRODUCER,
|
|
174
|
+
]);
|
|
175
|
+
/**
|
|
176
|
+
* Run every producer in `producers` against the shared context and
|
|
177
|
+
* flatten the result. The orchestrator calls this with `PRODUCERS`
|
|
178
|
+
* for production use; the playbook test calls it with an extended
|
|
179
|
+
* list to verify synthetic producers flow through.
|
|
180
|
+
*/
|
|
181
|
+
function runProducers(ctx, producers = exports.PRODUCERS) {
|
|
182
|
+
const out = [];
|
|
183
|
+
for (const producer of producers) {
|
|
184
|
+
out.push(...producer.produce(ctx));
|
|
185
|
+
}
|
|
186
|
+
return out;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Every kind currently contributed by some producer in `producers`.
|
|
190
|
+
* Convenience used by the contract test + by the orchestrator for
|
|
191
|
+
* logging "this run produced entries across N kinds."
|
|
192
|
+
*/
|
|
193
|
+
function wiredKinds(producers = exports.PRODUCERS) {
|
|
194
|
+
const out = new Set();
|
|
195
|
+
for (const p of producers)
|
|
196
|
+
for (const k of p.contributes)
|
|
197
|
+
out.add(k);
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=index.js.map
|