@hongmaple0820/scale-engine 0.48.0 → 0.50.1
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/README.en.md +2 -2
- package/README.md +2 -2
- package/dist/agents/evidenceDiscipline.d.ts +7 -0
- package/dist/agents/evidenceDiscipline.js +21 -0
- package/dist/agents/evidenceDiscipline.js.map +1 -0
- package/dist/agents/profiles.js +8 -1
- package/dist/agents/profiles.js.map +1 -1
- package/dist/agents/types.d.ts +1 -0
- package/dist/api/DashboardHttpConfig.d.ts +28 -0
- package/dist/api/DashboardHttpConfig.js +110 -0
- package/dist/api/DashboardHttpConfig.js.map +1 -0
- package/dist/api/cli.js +102 -11
- package/dist/api/cli.js.map +1 -1
- package/dist/api/http.d.ts +1 -0
- package/dist/api/http.js +50 -0
- package/dist/api/http.js.map +1 -0
- package/dist/artifact/types.d.ts +64 -0
- package/dist/artifact/types.js.map +1 -1
- package/dist/bootstrap/DependencyBootstrap.d.ts +1 -0
- package/dist/bootstrap/DependencyBootstrap.js +14 -3
- package/dist/bootstrap/DependencyBootstrap.js.map +1 -1
- package/dist/cli/cortexApplyCommand.d.ts +26 -0
- package/dist/cli/cortexApplyCommand.js +74 -0
- package/dist/cli/cortexApplyCommand.js.map +1 -0
- package/dist/cli/cortexCandidateCommands.d.ts +42 -0
- package/dist/cli/cortexCandidateCommands.js +119 -0
- package/dist/cli/cortexCandidateCommands.js.map +1 -0
- package/dist/cli/cortexCommands.d.ts +51 -0
- package/dist/cli/cortexCommands.js +127 -13
- package/dist/cli/cortexCommands.js.map +1 -1
- package/dist/cli/engineBootstrap.d.ts +1 -1
- package/dist/cli/engineBootstrap.js +2 -0
- package/dist/cli/engineBootstrap.js.map +1 -1
- package/dist/cli/evalCommands.js +13 -1
- package/dist/cli/evalCommands.js.map +1 -1
- package/dist/cli/phaseCommands.d.ts +81 -1
- package/dist/cli/phaseCommands.js +465 -31
- package/dist/cli/phaseCommands.js.map +1 -1
- package/dist/cli/runtimeSkillCommands.js +12 -2
- package/dist/cli/runtimeSkillCommands.js.map +1 -1
- package/dist/cli/shieldCommands.d.ts +1 -0
- package/dist/cli/shieldCommands.js +20 -7
- package/dist/cli/shieldCommands.js.map +1 -1
- package/dist/cli/workflowEvidenceCommands.d.ts +120 -0
- package/dist/cli/workflowEvidenceCommands.js +228 -2
- package/dist/cli/workflowEvidenceCommands.js.map +1 -1
- package/dist/cortex/AutoFixEventObservations.d.ts +11 -0
- package/dist/cortex/AutoFixEventObservations.js +72 -0
- package/dist/cortex/AutoFixEventObservations.js.map +1 -0
- package/dist/cortex/GateEvidenceObservations.d.ts +22 -0
- package/dist/cortex/GateEvidenceObservations.js +179 -0
- package/dist/cortex/GateEvidenceObservations.js.map +1 -0
- package/dist/cortex/GovernanceMetrics.d.ts +2 -0
- package/dist/cortex/GovernanceMetrics.js +112 -22
- package/dist/cortex/GovernanceMetrics.js.map +1 -1
- package/dist/cortex/InstinctApplicationRecorder.d.ts +28 -0
- package/dist/cortex/InstinctApplicationRecorder.js +145 -0
- package/dist/cortex/InstinctApplicationRecorder.js.map +1 -0
- package/dist/cortex/InstinctCandidateAudit.d.ts +3 -0
- package/dist/cortex/InstinctCandidateAudit.js +39 -0
- package/dist/cortex/InstinctCandidateAudit.js.map +1 -0
- package/dist/cortex/InstinctCandidateReview.d.ts +32 -0
- package/dist/cortex/InstinctCandidateReview.js +125 -0
- package/dist/cortex/InstinctCandidateReview.js.map +1 -0
- package/dist/cortex/InstinctExtractor.d.ts +1 -0
- package/dist/cortex/InstinctExtractor.js +24 -17
- package/dist/cortex/InstinctExtractor.js.map +1 -1
- package/dist/cortex/InstinctRuntimeEvidence.d.ts +14 -0
- package/dist/cortex/InstinctRuntimeEvidence.js +120 -0
- package/dist/cortex/InstinctRuntimeEvidence.js.map +1 -0
- package/dist/cortex/InstinctStore.d.ts +50 -4
- package/dist/cortex/InstinctStore.js +262 -48
- package/dist/cortex/InstinctStore.js.map +1 -1
- package/dist/cortex/InstinctValidation.d.ts +9 -0
- package/dist/cortex/InstinctValidation.js +55 -0
- package/dist/cortex/InstinctValidation.js.map +1 -0
- package/dist/cortex/SessionInjector.d.ts +1 -0
- package/dist/cortex/SessionInjector.js +28 -8
- package/dist/cortex/SessionInjector.js.map +1 -1
- package/dist/dashboard/DashboardServer.d.ts +79 -0
- package/dist/dashboard/DashboardServer.js +330 -6
- package/dist/dashboard/DashboardServer.js.map +1 -1
- package/dist/dashboard/spa/app.js +515 -0
- package/dist/dashboard/spa/components/DataTable.js +53 -0
- package/dist/dashboard/spa/components/EventStream.js +66 -0
- package/dist/dashboard/spa/components/LoadingState.js +39 -0
- package/dist/dashboard/spa/components/MetricCard.js +30 -0
- package/dist/dashboard/spa/components/Panel.js +27 -0
- package/dist/dashboard/spa/components/StatusBadge.js +51 -0
- package/dist/dashboard/spa/i18n.js +767 -0
- package/dist/dashboard/spa/index.html +463 -0
- package/dist/dashboard/spa/pages/costs.js +522 -0
- package/dist/dashboard/spa/pages/documents.js +540 -0
- package/dist/dashboard/spa/pages/knowledge.js +457 -0
- package/dist/dashboard/spa/pages/monitoring.js +361 -0
- package/dist/dashboard/spa/pages/overview.js +301 -0
- package/dist/dashboard/spa/pages/topology-renderers.js +251 -0
- package/dist/dashboard/spa/pages/topology.js +370 -0
- package/dist/dashboard/spa/pages/workflow-renderers.js +239 -0
- package/dist/dashboard/spa/pages/workflow.js +217 -0
- package/dist/env/EnvironmentDoctor.js +12 -7
- package/dist/env/EnvironmentDoctor.js.map +1 -1
- package/dist/eval/BenchmarkPublisher.d.ts +2 -0
- package/dist/eval/BenchmarkPublisher.js +43 -0
- package/dist/eval/BenchmarkPublisher.js.map +1 -1
- package/dist/eval/WorkflowEval.d.ts +9 -0
- package/dist/eval/WorkflowEval.js +348 -2
- package/dist/eval/WorkflowEval.js.map +1 -1
- package/dist/guardrails/ast/confirmers.d.ts +18 -0
- package/dist/guardrails/ast/confirmers.js +69 -0
- package/dist/guardrails/ast/confirmers.js.map +1 -0
- package/dist/guardrails/ast/parse.d.ts +20 -0
- package/dist/guardrails/ast/parse.js +51 -0
- package/dist/guardrails/ast/parse.js.map +1 -0
- package/dist/memory/MemoryBrain.d.ts +13 -0
- package/dist/memory/MemoryBrain.js +47 -0
- package/dist/memory/MemoryBrain.js.map +1 -1
- package/dist/memory/MemoryFabric.d.ts +1 -0
- package/dist/memory/MemoryFabric.js +12 -8
- package/dist/memory/MemoryFabric.js.map +1 -1
- package/dist/memory/MemoryLearning.d.ts +1 -0
- package/dist/memory/MemoryLearning.js +6 -3
- package/dist/memory/MemoryLearning.js.map +1 -1
- package/dist/memory/MemoryProviders.d.ts +8 -1
- package/dist/memory/MemoryProviders.js +143 -29
- package/dist/memory/MemoryProviders.js.map +1 -1
- package/dist/output/HTMLDocumentRenderer.d.ts +9 -0
- package/dist/output/HTMLDocumentRenderer.js +19 -0
- package/dist/output/HTMLDocumentRenderer.js.map +1 -1
- package/dist/review/FreshContextVerifier.d.ts +35 -0
- package/dist/review/FreshContextVerifier.js +120 -0
- package/dist/review/FreshContextVerifier.js.map +1 -0
- package/dist/review/JsonLlmClient.d.ts +37 -0
- package/dist/review/JsonLlmClient.js +94 -0
- package/dist/review/JsonLlmClient.js.map +1 -0
- package/dist/review/LlmJudge.d.ts +61 -0
- package/dist/review/LlmJudge.js +167 -0
- package/dist/review/LlmJudge.js.map +1 -0
- package/dist/runtime/AiOsRuntime.d.ts +14 -1
- package/dist/runtime/AiOsRuntime.js +59 -3
- package/dist/runtime/AiOsRuntime.js.map +1 -1
- package/dist/runtime/RuntimeDoctor.js +3 -1
- package/dist/runtime/RuntimeDoctor.js.map +1 -1
- package/dist/runtime/RuntimeEvidenceLedger.d.ts +6 -0
- package/dist/runtime/RuntimeEvidenceLedger.js +52 -1
- package/dist/runtime/RuntimeEvidenceLedger.js.map +1 -1
- package/dist/runtime/SessionLedger.d.ts +2 -0
- package/dist/runtime/SessionLedger.js +4 -0
- package/dist/runtime/SessionLedger.js.map +1 -1
- package/dist/setup/SetupVerification.js +53 -5
- package/dist/setup/SetupVerification.js.map +1 -1
- package/dist/shield/PolicyCompiler.js +73 -12
- package/dist/shield/PolicyCompiler.js.map +1 -1
- package/dist/shield/ProtectedPaths.js +4 -2
- package/dist/shield/ProtectedPaths.js.map +1 -1
- package/dist/skills/SkillCatalog.d.ts +2 -0
- package/dist/skills/SkillCatalog.js +8 -0
- package/dist/skills/SkillCatalog.js.map +1 -1
- package/dist/skills/SkillDoctor.d.ts +19 -2
- package/dist/skills/SkillDoctor.js +163 -13
- package/dist/skills/SkillDoctor.js.map +1 -1
- package/dist/tools/SafeCommandRunner.d.ts +1 -0
- package/dist/tools/SafeCommandRunner.js +1 -0
- package/dist/tools/SafeCommandRunner.js.map +1 -1
- package/dist/tools/ToolCapabilityRegistry.js +25 -3
- package/dist/tools/ToolCapabilityRegistry.js.map +1 -1
- package/dist/tools/ToolOrchestrator.js +21 -0
- package/dist/tools/ToolOrchestrator.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workflow/AgentLoopReadiness.d.ts +103 -0
- package/dist/workflow/AgentLoopReadiness.js +371 -0
- package/dist/workflow/AgentLoopReadiness.js.map +1 -0
- package/dist/workflow/BoundaryEnforcement.d.ts +60 -0
- package/dist/workflow/BoundaryEnforcement.js +182 -0
- package/dist/workflow/BoundaryEnforcement.js.map +1 -0
- package/dist/workflow/EcosystemReadinessGate.d.ts +46 -0
- package/dist/workflow/EcosystemReadinessGate.js +126 -0
- package/dist/workflow/EcosystemReadinessGate.js.map +1 -0
- package/dist/workflow/EngineeringStandards.js +67 -12
- package/dist/workflow/EngineeringStandards.js.map +1 -1
- package/dist/workflow/GateCatalog.js +21 -2
- package/dist/workflow/GateCatalog.js.map +1 -1
- package/dist/workflow/GovernanceTemplatePacks.js +2 -26
- package/dist/workflow/GovernanceTemplatePacks.js.map +1 -1
- package/dist/workflow/GovernanceTemplates.js +8 -1
- package/dist/workflow/GovernanceTemplates.js.map +1 -1
- package/dist/workflow/ProfileEnforcement.d.ts +7 -0
- package/dist/workflow/ProfileEnforcement.js +12 -0
- package/dist/workflow/ProfileEnforcement.js.map +1 -0
- package/dist/workflow/ReleaseDeploymentLedger.d.ts +63 -0
- package/dist/workflow/ReleaseDeploymentLedger.js +154 -0
- package/dist/workflow/ReleaseDeploymentLedger.js.map +1 -0
- package/dist/workflow/ReviewAnalyzer.js +50 -3
- package/dist/workflow/ReviewAnalyzer.js.map +1 -1
- package/dist/workflow/ReviewStore.d.ts +10 -0
- package/dist/workflow/ReviewStore.js.map +1 -1
- package/dist/workflow/SessionPreamble.d.ts +7 -0
- package/dist/workflow/SessionPreamble.js +48 -9
- package/dist/workflow/SessionPreamble.js.map +1 -1
- package/dist/workflow/SurfaceCoverage.d.ts +19 -0
- package/dist/workflow/SurfaceCoverage.js +57 -0
- package/dist/workflow/SurfaceCoverage.js.map +1 -0
- package/dist/workflow/VerificationCommands.d.ts +1 -0
- package/dist/workflow/VerificationCommands.js.map +1 -1
- package/dist/workflow/VerificationProfile.d.ts +5 -0
- package/dist/workflow/VerificationProfile.js +26 -0
- package/dist/workflow/VerificationProfile.js.map +1 -1
- package/dist/workflow/VerificationSchema.d.ts +3 -0
- package/dist/workflow/VerificationSchema.js +6 -0
- package/dist/workflow/VerificationSchema.js.map +1 -1
- package/dist/workflow/WorkflowEffectiveness.d.ts +97 -0
- package/dist/workflow/WorkflowEffectiveness.js +302 -0
- package/dist/workflow/WorkflowEffectiveness.js.map +1 -0
- package/dist/workflow/WorkflowEffectivenessRenderer.d.ts +2 -0
- package/dist/workflow/WorkflowEffectivenessRenderer.js +67 -0
- package/dist/workflow/WorkflowEffectivenessRenderer.js.map +1 -0
- package/dist/workflow/WorkflowEffectivenessScoring.d.ts +6 -0
- package/dist/workflow/WorkflowEffectivenessScoring.js +243 -0
- package/dist/workflow/WorkflowEffectivenessScoring.js.map +1 -0
- package/dist/workflow/gates/EnhancedGates.js +2 -0
- package/dist/workflow/gates/EnhancedGates.js.map +1 -1
- package/dist/workflow/gates/GateSystem.d.ts +16 -0
- package/dist/workflow/gates/GateSystem.js +208 -41
- package/dist/workflow/gates/GateSystem.js.map +1 -1
- package/dist/workflow/gates/MetaGovernanceGates.js +269 -8
- package/dist/workflow/gates/MetaGovernanceGates.js.map +1 -1
- package/dist/workflow/gates/TestIntegrityGate.d.ts +51 -0
- package/dist/workflow/gates/TestIntegrityGate.js +175 -0
- package/dist/workflow/gates/TestIntegrityGate.js.map +1 -0
- package/dist/workflow/types.d.ts +1 -1
- package/docs/guides/DEVELOPMENT_WORKFLOW.md +28 -0
- package/docs/reference/cli.md +2 -1
- package/docs/start/agent-governance-demo.md +1 -1
- package/docs/workflow/E2E_EXAMPLE.md +133 -0
- package/docs/workflow/README.md +7 -1
- package/docs/workflow/TEMPLATE_GUIDE.md +162 -0
- package/docs/workflow/templates/github-actions-scale-preflight.yml +4 -1
- package/docs/workflow/templates/plan.md +26 -0
- package/docs/workflow/templates/spec.md +28 -0
- package/package.json +7 -3
- package/scripts/workflow/run-vitest.mjs +123 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// SCALE Engine - P0+ Boundary & Constraint enforcement
|
|
2
|
+
//
|
|
3
|
+
// Two checks layered on top of the P0 six-element Spec contract:
|
|
4
|
+
//
|
|
5
|
+
// 1. Boundary enforcement — compares the files a task actually changed against
|
|
6
|
+
// the Spec's executional `boundaries` (allowed `files` globs + explicitly
|
|
7
|
+
// `forbidden` globs). Touching a forbidden path, or editing a file outside
|
|
8
|
+
// the declared allow-list, is reported as a violation.
|
|
9
|
+
//
|
|
10
|
+
// 2. Constraint coverage — checks each declared `constraint` (an invariant that
|
|
11
|
+
// must not regress) against the Spec's `verificationSurface`. A constraint
|
|
12
|
+
// with no surface guarding it is a silent-regression risk.
|
|
13
|
+
//
|
|
14
|
+
// Enforcement is profile-gated (mirrors G23's E1 escalation): under `default`
|
|
15
|
+
// and `auto` both checks are advisory — violations are surfaced as warnings and
|
|
16
|
+
// recorded as evidence but never flip `passed` or block ship. Under an enforced
|
|
17
|
+
// profile (`full`/`ci`/`strict`), the same findings are blocking: any boundary
|
|
18
|
+
// violation or unguarded constraint stops Task completion. The `enforced` flag
|
|
19
|
+
// threaded into the evaluators only sets the report's `advisory` mode; the
|
|
20
|
+
// detection logic is identical, so a re-verify under `default` cannot silence a
|
|
21
|
+
// finding, only downgrade how it is reported.
|
|
22
|
+
import { isEnforcedProfile } from './ProfileEnforcement.js';
|
|
23
|
+
/**
|
|
24
|
+
* Profiles in which boundary/constraint findings hard-block Task completion
|
|
25
|
+
* (decision E1, shared with G23). `default`/`auto` stay advisory; a profile
|
|
26
|
+
* whose name is or ends with `full`/`ci`/`strict` enforces.
|
|
27
|
+
*/
|
|
28
|
+
export function isEnforcedBoundaryProfile(profileName) {
|
|
29
|
+
return isEnforcedProfile(profileName);
|
|
30
|
+
}
|
|
31
|
+
export { isEnforcedProfile };
|
|
32
|
+
function norm(value) {
|
|
33
|
+
return value.replace(/\\/g, '/').trim().toLowerCase();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Translate a minimatch-style glob to an anchored, full-path RegExp.
|
|
37
|
+
* `**` matches across `/`, `*` matches within a segment, `?` matches one
|
|
38
|
+
* non-`/` char. All other regex metacharacters are escaped.
|
|
39
|
+
*/
|
|
40
|
+
function globToRegExp(glob) {
|
|
41
|
+
const body = glob
|
|
42
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape specials, leaving * and ?
|
|
43
|
+
.replace(/\*\*/g, '\u0000') // globstar placeholder
|
|
44
|
+
.replace(/\*/g, '[^/]*')
|
|
45
|
+
.replace(/\u0000/g, '.*')
|
|
46
|
+
.replace(/\?/g, '[^/]');
|
|
47
|
+
return new RegExp(`^${body}$`);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Does a (normalised) changed-file path match a boundary glob?
|
|
51
|
+
* Supports exact paths, bare directory prefixes (`src` ⇒ `src/**`) and globs.
|
|
52
|
+
*/
|
|
53
|
+
export function pathMatchesGlob(file, glob) {
|
|
54
|
+
const f = norm(file);
|
|
55
|
+
const g = norm(glob);
|
|
56
|
+
if (!f || !g)
|
|
57
|
+
return false;
|
|
58
|
+
if (f === g)
|
|
59
|
+
return true;
|
|
60
|
+
// Bare directory (no wildcards) acts as a recursive prefix.
|
|
61
|
+
if (!/[*?]/.test(g)) {
|
|
62
|
+
const dir = g.endsWith('/') ? g : `${g}/`;
|
|
63
|
+
if (f.startsWith(dir))
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
return globToRegExp(g).test(f);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compare the changed-file set against a Spec's executional boundaries.
|
|
75
|
+
* Returns `undefined` when there is nothing to enforce (no boundaries, or
|
|
76
|
+
* neither `files` nor `forbidden` declared).
|
|
77
|
+
*/
|
|
78
|
+
export function evaluateBoundaries(changedFiles, boundaries, enforced = false) {
|
|
79
|
+
if (!boundaries)
|
|
80
|
+
return undefined;
|
|
81
|
+
const allowed = (boundaries.files ?? []).map(norm).filter(Boolean);
|
|
82
|
+
const forbidden = (boundaries.forbidden ?? []).map(norm).filter(Boolean);
|
|
83
|
+
if (allowed.length === 0 && forbidden.length === 0)
|
|
84
|
+
return undefined;
|
|
85
|
+
const files = [...new Set((changedFiles ?? []).map(f => norm(f ?? '')).filter(Boolean))];
|
|
86
|
+
const violations = [];
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
const hitForbidden = forbidden.find(glob => pathMatchesGlob(file, glob));
|
|
89
|
+
if (hitForbidden) {
|
|
90
|
+
violations.push({ file, kind: 'forbidden-touched', matchedGlob: hitForbidden });
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (allowed.length > 0 && !allowed.some(glob => pathMatchesGlob(file, glob))) {
|
|
94
|
+
violations.push({ file, kind: 'outside-allowed' });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
declaredAllowed: allowed.length,
|
|
99
|
+
declaredForbidden: forbidden.length,
|
|
100
|
+
changedFiles: files.length,
|
|
101
|
+
violations,
|
|
102
|
+
advisory: !enforced,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function significantTokens(value) {
|
|
106
|
+
return [
|
|
107
|
+
...new Set(norm(value)
|
|
108
|
+
.split(/[^a-z0-9]+/)
|
|
109
|
+
.filter(token => token.length >= 4)),
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A constraint is "covered" when at least one of its significant tokens appears
|
|
114
|
+
* in some verificationSurface item — i.e. there is a declared check that could
|
|
115
|
+
* catch a regression of that invariant.
|
|
116
|
+
*/
|
|
117
|
+
function constraintCovered(constraint, surfaces) {
|
|
118
|
+
const tokens = significantTokens(constraint);
|
|
119
|
+
if (tokens.length === 0)
|
|
120
|
+
return false;
|
|
121
|
+
return surfaces.some(surface => tokens.some(token => surface.includes(token)));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Check that every declared constraint is guarded by some verificationSurface
|
|
125
|
+
* item. Returns `undefined` when no constraints are declared.
|
|
126
|
+
*/
|
|
127
|
+
export function evaluateConstraints(constraints, verificationSurface, enforced = false) {
|
|
128
|
+
const declared = (constraints ?? []).map(c => c.trim()).filter(Boolean);
|
|
129
|
+
if (declared.length === 0)
|
|
130
|
+
return undefined;
|
|
131
|
+
const surfaces = (verificationSurface ?? []).map(norm).filter(Boolean);
|
|
132
|
+
const uncovered = declared.filter(constraint => !constraintCovered(constraint, surfaces));
|
|
133
|
+
return {
|
|
134
|
+
declared: declared.length,
|
|
135
|
+
covered: declared.length - uncovered.length,
|
|
136
|
+
uncovered,
|
|
137
|
+
advisory: !enforced,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Count the findings that block Task completion under an enforced profile:
|
|
142
|
+
* every boundary violation plus every unguarded constraint. Returns 0 when both
|
|
143
|
+
* reports are clean or undefined. The caller decides whether to act on the
|
|
144
|
+
* count based on the active profile (advisory reports are not blocked even when
|
|
145
|
+
* this count is non-zero).
|
|
146
|
+
*/
|
|
147
|
+
export function countBoundaryBlockers(boundary, constraint) {
|
|
148
|
+
return (boundary?.violations.length ?? 0) + (constraint?.uncovered.length ?? 0);
|
|
149
|
+
}
|
|
150
|
+
/** Render boundary warning lines (empty when there is nothing to warn about). */
|
|
151
|
+
export function formatBoundaryWarnings(report) {
|
|
152
|
+
if (!report || report.violations.length === 0)
|
|
153
|
+
return [];
|
|
154
|
+
const tag = report.advisory ? '[WARN]' : '[BLOCKER]';
|
|
155
|
+
const mode = report.advisory ? 'advisory, not blocking' : 'blocking under enforced profile';
|
|
156
|
+
const lines = [
|
|
157
|
+
`${tag} boundary enforcement: ${report.violations.length} violation(s) (${mode})`,
|
|
158
|
+
];
|
|
159
|
+
for (const v of report.violations) {
|
|
160
|
+
lines.push(v.kind === 'forbidden-touched'
|
|
161
|
+
? ` [FORBIDDEN] ${v.file} (matched ${v.matchedGlob})`
|
|
162
|
+
: ` [OUTSIDE-ALLOWED] ${v.file}`);
|
|
163
|
+
}
|
|
164
|
+
lines.push(' Keep edits inside the Spec boundaries (or widen them in the Spec).');
|
|
165
|
+
return lines;
|
|
166
|
+
}
|
|
167
|
+
/** Render constraint-coverage warning lines (empty when fully covered). */
|
|
168
|
+
export function formatConstraintWarnings(report) {
|
|
169
|
+
if (!report || report.uncovered.length === 0)
|
|
170
|
+
return [];
|
|
171
|
+
const tag = report.advisory ? '[WARN]' : '[BLOCKER]';
|
|
172
|
+
const mode = report.advisory ? 'advisory, not blocking' : 'blocking under enforced profile';
|
|
173
|
+
const lines = [
|
|
174
|
+
`${tag} constraint coverage: ${report.covered}/${report.declared} guarded by verificationSurface (${mode})`,
|
|
175
|
+
];
|
|
176
|
+
for (const constraint of report.uncovered) {
|
|
177
|
+
lines.push(` [UNGUARDED] ${constraint}`);
|
|
178
|
+
}
|
|
179
|
+
lines.push(' Add a verificationSurface item that would catch a regression of each constraint.');
|
|
180
|
+
return lines;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=BoundaryEnforcement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BoundaryEnforcement.js","sourceRoot":"","sources":["../../src/workflow/BoundaryEnforcement.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { verifySetup, type SetupVerificationReport } from '../setup/SetupVerification.js';
|
|
2
|
+
import { inspectWorkflowSkills, type SkillDoctorReport } from '../skills/SkillDoctor.js';
|
|
3
|
+
import type { VerificationPolicy } from './VerificationProfile.js';
|
|
4
|
+
export type EcosystemReadinessGateMode = 'off' | 'warn' | 'block';
|
|
5
|
+
export type EcosystemReadinessSkillScope = 'required' | 'recommended' | 'all';
|
|
6
|
+
export interface EcosystemReadinessGateReport {
|
|
7
|
+
mode: EcosystemReadinessGateMode;
|
|
8
|
+
checked: boolean;
|
|
9
|
+
ok: boolean;
|
|
10
|
+
blocked: boolean;
|
|
11
|
+
packIds: string[];
|
|
12
|
+
summary: {
|
|
13
|
+
blockingIssues: string[];
|
|
14
|
+
warningCount: number;
|
|
15
|
+
installedTools: number;
|
|
16
|
+
totalTools: number;
|
|
17
|
+
missingTools: string[];
|
|
18
|
+
installedWorkflowSkills: number;
|
|
19
|
+
totalWorkflowSkills: number;
|
|
20
|
+
missingWorkflowSkills: string[];
|
|
21
|
+
missingRequiredWorkflowSkills: string[];
|
|
22
|
+
missingRecommendedWorkflowSkills: string[];
|
|
23
|
+
missingOptionalWorkflowSkills: string[];
|
|
24
|
+
blockingMissingWorkflowSkills: string[];
|
|
25
|
+
skillScope: EcosystemReadinessSkillScope;
|
|
26
|
+
};
|
|
27
|
+
setup?: SetupVerificationReport;
|
|
28
|
+
skillDoctor?: SkillDoctorReport;
|
|
29
|
+
warnings: string[];
|
|
30
|
+
recommendations: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface EcosystemReadinessGateOptions {
|
|
33
|
+
projectDir: string;
|
|
34
|
+
scaleDir: string;
|
|
35
|
+
policy: VerificationPolicy;
|
|
36
|
+
checked?: boolean;
|
|
37
|
+
skipReason?: string;
|
|
38
|
+
deps?: {
|
|
39
|
+
verifySetup?: typeof verifySetup;
|
|
40
|
+
inspectWorkflowSkills?: typeof inspectWorkflowSkills;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export declare function evaluateEcosystemReadinessGate(options: EcosystemReadinessGateOptions): Promise<EcosystemReadinessGateReport>;
|
|
44
|
+
export declare function normalizeEcosystemReadinessGateMode(value: unknown): EcosystemReadinessGateMode;
|
|
45
|
+
export declare function normalizeEcosystemReadinessPacks(value: unknown): string[];
|
|
46
|
+
export declare function normalizeEcosystemReadinessSkillScope(value: unknown): EcosystemReadinessSkillScope;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { verifySetup } from '../setup/SetupVerification.js';
|
|
2
|
+
import { inspectWorkflowSkills } from '../skills/SkillDoctor.js';
|
|
3
|
+
const DEFAULT_ECOSYSTEM_PACKS = ['full'];
|
|
4
|
+
const VALID_ECOSYSTEM_PACKS = new Set(['ui', 'memory', 'knowledge', 'external-cli', 'full']);
|
|
5
|
+
export async function evaluateEcosystemReadinessGate(options) {
|
|
6
|
+
const mode = normalizeEcosystemReadinessGateMode(options.policy.ecosystemReadinessGate);
|
|
7
|
+
const packIds = normalizeEcosystemReadinessPacks(options.policy.ecosystemReadinessPacks);
|
|
8
|
+
const skillScope = normalizeEcosystemReadinessSkillScope(options.policy.ecosystemReadinessSkillScope);
|
|
9
|
+
if (mode === 'off' || options.checked === false) {
|
|
10
|
+
const reason = options.skipReason ?? (mode === 'off' ? 'ecosystem readiness gate is disabled by policy' : 'ecosystem readiness gate skipped for this preflight profile');
|
|
11
|
+
return {
|
|
12
|
+
mode,
|
|
13
|
+
checked: false,
|
|
14
|
+
ok: true,
|
|
15
|
+
blocked: false,
|
|
16
|
+
packIds,
|
|
17
|
+
summary: {
|
|
18
|
+
blockingIssues: [],
|
|
19
|
+
warningCount: 0,
|
|
20
|
+
installedTools: 0,
|
|
21
|
+
totalTools: 0,
|
|
22
|
+
missingTools: [],
|
|
23
|
+
installedWorkflowSkills: 0,
|
|
24
|
+
totalWorkflowSkills: 0,
|
|
25
|
+
missingWorkflowSkills: [],
|
|
26
|
+
missingRequiredWorkflowSkills: [],
|
|
27
|
+
missingRecommendedWorkflowSkills: [],
|
|
28
|
+
missingOptionalWorkflowSkills: [],
|
|
29
|
+
blockingMissingWorkflowSkills: [],
|
|
30
|
+
skillScope,
|
|
31
|
+
},
|
|
32
|
+
warnings: [reason],
|
|
33
|
+
recommendations: [],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const setup = await (options.deps?.verifySetup ?? verifySetup)({
|
|
37
|
+
projectDir: options.projectDir,
|
|
38
|
+
scaleDir: options.scaleDir,
|
|
39
|
+
packIds,
|
|
40
|
+
});
|
|
41
|
+
const skillDoctor = (options.deps?.inspectWorkflowSkills ?? inspectWorkflowSkills)({
|
|
42
|
+
projectDir: options.projectDir,
|
|
43
|
+
scaleDir: options.scaleDir,
|
|
44
|
+
});
|
|
45
|
+
const missingTools = setup.toolCapabilities.tools
|
|
46
|
+
.filter(tool => !tool.installed)
|
|
47
|
+
.map(tool => tool.id);
|
|
48
|
+
const missingWorkflowSkills = skillDoctor.skills
|
|
49
|
+
.filter(skill => skill.status === 'missing')
|
|
50
|
+
.map(skill => skill.id);
|
|
51
|
+
const missingRequiredWorkflowSkills = skillDoctor.missingByReadiness.required;
|
|
52
|
+
const missingRecommendedWorkflowSkills = skillDoctor.missingByReadiness.recommended;
|
|
53
|
+
const missingOptionalWorkflowSkills = skillDoctor.missingByReadiness.optional;
|
|
54
|
+
const blockingMissingWorkflowSkills = missingWorkflowSkillsForScope(skillDoctor, skillScope);
|
|
55
|
+
const workflowSkillsReadyForScope = blockingMissingWorkflowSkills.length === 0;
|
|
56
|
+
const blockingMissingWorkflowSkillSet = new Set(blockingMissingWorkflowSkills);
|
|
57
|
+
const nonBlockingMissingWorkflowSkills = missingWorkflowSkills
|
|
58
|
+
.filter(skill => !blockingMissingWorkflowSkillSet.has(skill));
|
|
59
|
+
const blockingIssues = [
|
|
60
|
+
...setup.summary.blockingIssues,
|
|
61
|
+
...(workflowSkillsReadyForScope ? [] : [`Missing ${skillScope} workflow skills: ${blockingMissingWorkflowSkills.join(', ')}`]),
|
|
62
|
+
];
|
|
63
|
+
const ok = setup.ok && workflowSkillsReadyForScope;
|
|
64
|
+
const warnings = [
|
|
65
|
+
...setup.warnings,
|
|
66
|
+
...(setup.ok ? [] : [`Setup readiness is not OK for pack(s): ${packIds.join(', ')}`]),
|
|
67
|
+
...(workflowSkillsReadyForScope ? [] : [`Workflow skill readiness is not OK for ${skillScope} scope: ${blockingMissingWorkflowSkills.join(', ')}`]),
|
|
68
|
+
...(nonBlockingMissingWorkflowSkills.length === 0 ? [] : [`Non-blocking workflow skills missing: ${nonBlockingMissingWorkflowSkills.join(', ')}`]),
|
|
69
|
+
];
|
|
70
|
+
return {
|
|
71
|
+
mode,
|
|
72
|
+
checked: true,
|
|
73
|
+
ok,
|
|
74
|
+
blocked: mode === 'block' && (!setup.ok || !workflowSkillsReadyForScope),
|
|
75
|
+
packIds,
|
|
76
|
+
summary: {
|
|
77
|
+
blockingIssues,
|
|
78
|
+
warningCount: warnings.length,
|
|
79
|
+
installedTools: setup.summary.installedTools,
|
|
80
|
+
totalTools: setup.summary.totalTools,
|
|
81
|
+
missingTools,
|
|
82
|
+
installedWorkflowSkills: skillDoctor.installed,
|
|
83
|
+
totalWorkflowSkills: skillDoctor.total,
|
|
84
|
+
missingWorkflowSkills,
|
|
85
|
+
missingRequiredWorkflowSkills,
|
|
86
|
+
missingRecommendedWorkflowSkills,
|
|
87
|
+
missingOptionalWorkflowSkills,
|
|
88
|
+
blockingMissingWorkflowSkills,
|
|
89
|
+
skillScope,
|
|
90
|
+
},
|
|
91
|
+
setup,
|
|
92
|
+
skillDoctor,
|
|
93
|
+
warnings,
|
|
94
|
+
recommendations: setup.recommendations,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export function normalizeEcosystemReadinessGateMode(value) {
|
|
98
|
+
if (value === 'off' || value === 'warn' || value === 'block')
|
|
99
|
+
return value;
|
|
100
|
+
return 'warn';
|
|
101
|
+
}
|
|
102
|
+
export function normalizeEcosystemReadinessPacks(value) {
|
|
103
|
+
if (!Array.isArray(value))
|
|
104
|
+
return [...DEFAULT_ECOSYSTEM_PACKS];
|
|
105
|
+
const packs = value
|
|
106
|
+
.map(item => String(item).trim())
|
|
107
|
+
.filter(item => VALID_ECOSYSTEM_PACKS.has(item));
|
|
108
|
+
return packs.length > 0 ? [...new Set(packs)] : [...DEFAULT_ECOSYSTEM_PACKS];
|
|
109
|
+
}
|
|
110
|
+
export function normalizeEcosystemReadinessSkillScope(value) {
|
|
111
|
+
if (value === 'required' || value === 'recommended' || value === 'all')
|
|
112
|
+
return value;
|
|
113
|
+
return 'required';
|
|
114
|
+
}
|
|
115
|
+
function missingWorkflowSkillsForScope(skillDoctor, scope) {
|
|
116
|
+
if (scope === 'all')
|
|
117
|
+
return skillDoctor.skills.filter(skill => skill.status === 'missing').map(skill => skill.id);
|
|
118
|
+
if (scope === 'recommended') {
|
|
119
|
+
return [
|
|
120
|
+
...skillDoctor.missingByReadiness.required,
|
|
121
|
+
...skillDoctor.missingByReadiness.recommended,
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
return skillDoctor.missingByReadiness.required;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=EcosystemReadinessGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EcosystemReadinessGate.js","sourceRoot":"","sources":["../../src/workflow/EcosystemReadinessGate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgC,MAAM,+BAA+B,CAAA;AACzF,OAAO,EAAE,qBAAqB,EAA0B,MAAM,0BAA0B,CAAA;AA6CxF,MAAM,uBAAuB,GAAG,CAAC,MAAM,CAAC,CAAA;AACxC,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC,CAAA;AAE5F,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,OAAsC;IAEtC,MAAM,IAAI,GAAG,mCAAmC,CAAC,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAA;IACvF,MAAM,OAAO,GAAG,gCAAgC,CAAC,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAA;IACxF,MAAM,UAAU,GAAG,qCAAqC,CAAC,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAAC,CAAA;IACrG,IAAI,IAAI,KAAK,KAAK,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,gDAAgD,CAAC,CAAC,CAAC,6DAA6D,CAAC,CAAA;QACxK,OAAO;YACL,IAAI;YACJ,OAAO,EAAE,KAAK;YACd,EAAE,EAAE,IAAI;YACR,OAAO,EAAE,KAAK;YACd,OAAO;YACP,OAAO,EAAE;gBACP,cAAc,EAAE,EAAE;gBAClB,YAAY,EAAE,CAAC;gBACf,cAAc,EAAE,CAAC;gBACjB,UAAU,EAAE,CAAC;gBACb,YAAY,EAAE,EAAE;gBAChB,uBAAuB,EAAE,CAAC;gBAC1B,mBAAmB,EAAE,CAAC;gBACtB,qBAAqB,EAAE,EAAE;gBACzB,6BAA6B,EAAE,EAAE;gBACjC,gCAAgC,EAAE,EAAE;gBACpC,6BAA6B,EAAE,EAAE;gBACjC,6BAA6B,EAAE,EAAE;gBACjC,UAAU;aACX;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;YAClB,eAAe,EAAE,EAAE;SACpB,CAAA;IACH,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,IAAI,WAAW,CAAC,CAAC;QAC7D,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,OAAO;KACR,CAAC,CAAA;IACF,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,qBAAqB,IAAI,qBAAqB,CAAC,CAAC;QACjF,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC,CAAA;IACF,MAAM,YAAY,GAAG,KAAK,CAAC,gBAAgB,CAAC,KAAK;SAC9C,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;SAC/B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvB,MAAM,qBAAqB,GAAG,WAAW,CAAC,MAAM;SAC7C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC;SAC3C,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IACzB,MAAM,6BAA6B,GAAG,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAA;IAC7E,MAAM,gCAAgC,GAAG,WAAW,CAAC,kBAAkB,CAAC,WAAW,CAAA;IACnF,MAAM,6BAA6B,GAAG,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAA;IAC7E,MAAM,6BAA6B,GAAG,6BAA6B,CAAC,WAAW,EAAE,UAAU,CAAC,CAAA;IAC5F,MAAM,2BAA2B,GAAG,6BAA6B,CAAC,MAAM,KAAK,CAAC,CAAA;IAC9E,MAAM,+BAA+B,GAAG,IAAI,GAAG,CAAC,6BAA6B,CAAC,CAAA;IAC9E,MAAM,gCAAgC,GAAG,qBAAqB;SAC3D,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,+BAA+B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;IAC/D,MAAM,cAAc,GAAG;QACrB,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc;QAC/B,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,UAAU,qBAAqB,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;KAC/H,CAAA;IACD,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,2BAA2B,CAAA;IAClD,MAAM,QAAQ,GAAG;QACf,GAAG,KAAK,CAAC,QAAQ;QACjB,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,0CAA0C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrF,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,0CAA0C,UAAU,WAAW,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnJ,GAAG,CAAC,gCAAgC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,yCAAyC,gCAAgC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;KACnJ,CAAA;IAED,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,IAAI;QACb,EAAE;QACF,OAAO,EAAE,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,2BAA2B,CAAC;QACxE,OAAO;QACP,OAAO,EAAE;YACP,cAAc;YACd,YAAY,EAAE,QAAQ,CAAC,MAAM;YAC7B,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc;YAC5C,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU;YACpC,YAAY;YACZ,uBAAuB,EAAE,WAAW,CAAC,SAAS;YAC9C,mBAAmB,EAAE,WAAW,CAAC,KAAK;YACtC,qBAAqB;YACrB,6BAA6B;YAC7B,gCAAgC;YAChC,6BAA6B;YAC7B,6BAA6B;YAC7B,UAAU;SACX;QACD,KAAK;QACL,WAAW;QACX,QAAQ;QACR,eAAe,EAAE,KAAK,CAAC,eAAe;KACvC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,KAAc;IAChE,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO;QAAE,OAAO,KAAK,CAAA;IAC1E,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,gCAAgC,CAAC,KAAc;IAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,uBAAuB,CAAC,CAAA;IAC9D,MAAM,KAAK,GAAG,KAAK;SAChB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;SAChC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;IAClD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAA;AAC9E,CAAC;AAED,MAAM,UAAU,qCAAqC,CAAC,KAAc;IAClE,IAAI,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,aAAa,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,KAAK,CAAA;IACpF,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,6BAA6B,CACpC,WAA8B,EAC9B,KAAmC;IAEnC,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IACjH,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;QAC5B,OAAO;YACL,GAAG,WAAW,CAAC,kBAAkB,CAAC,QAAQ;YAC1C,GAAG,WAAW,CAAC,kBAAkB,CAAC,WAAW;SAC9C,CAAA;IACH,CAAC;IACD,OAAO,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAA;AAChD,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { extname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { createAstConfirmer } from '../guardrails/ast/confirmers.js';
|
|
3
4
|
const DEFAULT_SOURCE_DIRECTORIES = ['src', 'app', 'packages', 'services', 'cmd', 'internal', 'pkg'];
|
|
4
5
|
const DEFAULT_IGNORED_DIRECTORIES = [
|
|
5
6
|
'.git',
|
|
@@ -379,6 +380,11 @@ function scanFile(projectDir, absolutePath, policy, frameworks) {
|
|
|
379
380
|
const content = readFileSync(absolutePath, 'utf-8');
|
|
380
381
|
const lines = content.split(/\r?\n/);
|
|
381
382
|
const findings = [];
|
|
383
|
+
// AST confirmation layer (P1.1): parse once per file so the regex pre-filter
|
|
384
|
+
// hits below can be confirmed against the real AST. null = parse failed, in
|
|
385
|
+
// which case every confirmer falls back to the raw regex result.
|
|
386
|
+
const ext = extname(absolutePath);
|
|
387
|
+
const astConfirmer = createAstConfirmer(content, { jsx: ext === '.tsx' || ext === '.jsx' });
|
|
382
388
|
if (lines.length > policy.maxFileLines) {
|
|
383
389
|
findings.push({
|
|
384
390
|
severity: 'warn',
|
|
@@ -394,15 +400,15 @@ function scanFile(projectDir, absolutePath, policy, frameworks) {
|
|
|
394
400
|
const line = lines[index];
|
|
395
401
|
const startedInsideTemplateLiteral = insideTemplateLiteral;
|
|
396
402
|
insideTemplateLiteral = updateTemplateLiteralState(line, insideTemplateLiteral);
|
|
397
|
-
if (startedInsideTemplateLiteral || isNonExecutablePatternLine(line))
|
|
403
|
+
if (startedInsideTemplateLiteral || isNonExecutablePatternLine(line) || isSecurityRuleDefinitionLine(path, line))
|
|
398
404
|
continue;
|
|
399
405
|
const lineNumber = index + 1;
|
|
400
|
-
findings.push(...scanLine(path, line, lineNumber, policy, frameworks));
|
|
406
|
+
findings.push(...scanLine(path, line, lineNumber, policy, frameworks, astConfirmer));
|
|
401
407
|
}
|
|
402
|
-
findings.push(...findEmptyCatchBlocks(path, lines));
|
|
408
|
+
findings.push(...findEmptyCatchBlocks(path, lines, astConfirmer));
|
|
403
409
|
return dedupeFindings(findings);
|
|
404
410
|
}
|
|
405
|
-
function scanLine(path, line, lineNumber, policy, frameworks) {
|
|
411
|
+
function scanLine(path, line, lineNumber, policy, frameworks, ast) {
|
|
406
412
|
const findings = [];
|
|
407
413
|
const sensitiveMatcher = sensitiveFieldPattern(policy);
|
|
408
414
|
const evidence = line.trim().slice(0, 160);
|
|
@@ -467,7 +473,7 @@ function scanLine(path, line, lineNumber, policy, frameworks) {
|
|
|
467
473
|
fix: 'Use text rendering or sanitize trusted HTML with an approved sanitizer.',
|
|
468
474
|
});
|
|
469
475
|
}
|
|
470
|
-
if (/\beval\s*\(|new\s+Function\s*\(/.test(line)) {
|
|
476
|
+
if (/\beval\s*\(|new\s+Function\s*\(/.test(line) && (!ast || ast.hasUnsafeCodeExecution(lineNumber))) {
|
|
471
477
|
findings.push({
|
|
472
478
|
severity: 'fail',
|
|
473
479
|
category: 'security',
|
|
@@ -479,7 +485,7 @@ function scanLine(path, line, lineNumber, policy, frameworks) {
|
|
|
479
485
|
fix: 'Replace eval or Function with a typed parser, dispatch table, or safe interpreter.',
|
|
480
486
|
});
|
|
481
487
|
}
|
|
482
|
-
if (/^\s*(?:\/\/|\/\*)\s*@ts-ignore\b/.test(line)) {
|
|
488
|
+
if (/^\s*(?:\/\/|\/\*)\s*@ts-ignore\b/.test(line) && (!ast || ast.hasTsIgnore(lineNumber))) {
|
|
483
489
|
findings.push({
|
|
484
490
|
severity: 'fail',
|
|
485
491
|
category: 'code-quality',
|
|
@@ -491,7 +497,7 @@ function scanLine(path, line, lineNumber, policy, frameworks) {
|
|
|
491
497
|
fix: 'Fix the type boundary or use a narrow typed adapter with a documented reason.',
|
|
492
498
|
});
|
|
493
499
|
}
|
|
494
|
-
if (/\bas\s+any\b|:\s*any\b|<any\b|Array<any>|Promise<any>|Record<[^>]+,\s*any>/.test(line)) {
|
|
500
|
+
if (/\bas\s+any\b|:\s*any\b|<any\b|Array<any>|Promise<any>|Record<[^>]+,\s*any>/.test(line) && (!ast || ast.hasAnyType(lineNumber))) {
|
|
495
501
|
findings.push({
|
|
496
502
|
severity: 'warn',
|
|
497
503
|
category: 'code-quality',
|
|
@@ -529,12 +535,16 @@ function scanLine(path, line, lineNumber, policy, frameworks) {
|
|
|
529
535
|
}
|
|
530
536
|
return findings;
|
|
531
537
|
}
|
|
532
|
-
function findEmptyCatchBlocks(path, lines) {
|
|
538
|
+
function findEmptyCatchBlocks(path, lines, ast) {
|
|
533
539
|
const findings = [];
|
|
540
|
+
// AST confirmation: only emit when the catch block genuinely has zero
|
|
541
|
+
// statements. Falls back to the regex result when the file did not parse.
|
|
542
|
+
const confirm = (line) => !ast || ast.hasEmptyCatch(line);
|
|
534
543
|
for (let index = 0; index < lines.length; index += 1) {
|
|
535
544
|
const line = lines[index];
|
|
536
545
|
if (/catch\s*(?:\([^)]*\))?\s*\{\s*(?:\/\*.*?\*\/|\/\/.*)?\s*\}/.test(line)) {
|
|
537
|
-
|
|
546
|
+
if (confirm(index + 1))
|
|
547
|
+
findings.push(emptyCatchFinding(path, index + 1, line));
|
|
538
548
|
continue;
|
|
539
549
|
}
|
|
540
550
|
if (!/catch\s*(?:\([^)]*\))?\s*\{\s*$/.test(line))
|
|
@@ -543,7 +553,7 @@ function findEmptyCatchBlocks(path, lines) {
|
|
|
543
553
|
const trimmed = next.trim();
|
|
544
554
|
if (trimmed === '' || trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*'))
|
|
545
555
|
continue;
|
|
546
|
-
if (/^}\s*[),;]?$/.test(trimmed))
|
|
556
|
+
if (/^}\s*[),;]?$/.test(trimmed) && confirm(index + 1))
|
|
547
557
|
findings.push(emptyCatchFinding(path, index + 1, line));
|
|
548
558
|
break;
|
|
549
559
|
}
|
|
@@ -944,7 +954,14 @@ function sensitiveFieldPattern(policy) {
|
|
|
944
954
|
return new RegExp(`\\b(?:${fields})\\b`, 'i');
|
|
945
955
|
}
|
|
946
956
|
function isLogCall(line) {
|
|
947
|
-
|
|
957
|
+
for (const match of line.matchAll(/\b(?:console\.(?:log|debug|info|warn|error)|logger\.(?:trace|debug|info|warn|error|fatal)|log(?:ger)?\.(?:trace|debug|info|warn|error|fatal)|log[A-Za-z0-9_]*\s*\()/g)) {
|
|
958
|
+
if (match.index !== undefined &&
|
|
959
|
+
!isInsideQuotedString(line, match.index) &&
|
|
960
|
+
!isInsideRegexLiteral(line, match.index)) {
|
|
961
|
+
return true;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
return false;
|
|
948
965
|
}
|
|
949
966
|
function isAdHocOutputCall(line) {
|
|
950
967
|
for (const match of line.matchAll(/\bconsole\.(?:log|debug|info|warn|error)\s*\(|\bfmt\.Print(?:f|ln)?\s*\(|\bprint(?:ln)?\s*\(|\bSystem\.out\.print(?:ln)?\s*\(|\bConsole\.Write(?:Line)?\s*\(|\bprintln!\s*\(/g)) {
|
|
@@ -961,7 +978,16 @@ function isHardcodedSecret(line, policy) {
|
|
|
961
978
|
const match = new RegExp(`\\b\\w*(?:${fields})\\w*\\b\\s*[:=]\\s*(['"\`])([^'"\`]{12,})\\1`, 'i').exec(line);
|
|
962
979
|
if (!match)
|
|
963
980
|
return false;
|
|
964
|
-
return
|
|
981
|
+
return !isAllowedSecretLiteralReference(match[2]);
|
|
982
|
+
}
|
|
983
|
+
function isAllowedSecretLiteralReference(value) {
|
|
984
|
+
if (/\b(example|sample|placeholder|changeme|replace-me|dummy|test-value)\b/i.test(value))
|
|
985
|
+
return true;
|
|
986
|
+
if (/\b(?:process\.env|import\.meta\.env|Deno\.env|getenv)\b/.test(value))
|
|
987
|
+
return true;
|
|
988
|
+
if (value.includes('${'))
|
|
989
|
+
return true;
|
|
990
|
+
return /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+$/.test(value);
|
|
965
991
|
}
|
|
966
992
|
function isRawSqlConstruction(line) {
|
|
967
993
|
return /\b(?:query|execute|exec|raw|rawQuery)\s*\(/i.test(line) &&
|
|
@@ -994,6 +1020,35 @@ function isNonExecutablePatternLine(line) {
|
|
|
994
1020
|
/^pattern:\s*\/.*\/[dgimsuy]*,?$/.test(trimmed) ||
|
|
995
1021
|
/\(\s*\/.*\/[dgimsuy]*\.(?:test|exec)\(/.test(trimmed);
|
|
996
1022
|
}
|
|
1023
|
+
function isSecurityRuleDefinitionLine(path, line) {
|
|
1024
|
+
if (!isSecurityRuleSource(path))
|
|
1025
|
+
return false;
|
|
1026
|
+
const trimmed = line.trim();
|
|
1027
|
+
if (/^id:\s*['"`][^'"`]+['"`],?$/.test(trimmed))
|
|
1028
|
+
return true;
|
|
1029
|
+
if (/^\{?\s*pattern:\s*\/.*\/[dgimsuy]*,?/.test(trimmed))
|
|
1030
|
+
return true;
|
|
1031
|
+
if (/^patterns:\s*\[/.test(trimmed))
|
|
1032
|
+
return true;
|
|
1033
|
+
if (/^\/.*\/[dgimsuy]*,?(?:\s*\/\/.*)?$/.test(trimmed))
|
|
1034
|
+
return true;
|
|
1035
|
+
if (/^(?:const|let|var)\s+\w*pattern\w*\s*=\s*\/.*\/[dgimsuy]*/i.test(trimmed))
|
|
1036
|
+
return true;
|
|
1037
|
+
if (/^(?:name|title|description|recommendation|remediation):\s*['"`].*(?:dangerouslySetInnerHTML|innerHTML|document\.write|eval\(|new Function|curl pipe|shell:\s*true)/i.test(trimmed))
|
|
1038
|
+
return true;
|
|
1039
|
+
return /^(?:if\s*\(|return\s+)?\/?.*(?:dangerouslySetInnerHTML|innerHTML|document\.write|eval\(|new Function|curl pipe|shell:\s*true).*\/[dgimsuy]*\.test\(/i.test(trimmed) ||
|
|
1040
|
+
/^(?:\/\/|\/\*\*?|\*)\s*.*(?:dangerouslySetInnerHTML|innerHTML|document\.write|eval\(|new Function|curl pipe|shell:\s*true)/i.test(trimmed);
|
|
1041
|
+
}
|
|
1042
|
+
function isSecurityRuleSource(path) {
|
|
1043
|
+
return [
|
|
1044
|
+
'src/guardrails/advancedDetectors.ts',
|
|
1045
|
+
'src/guardrails/ast/confirmers.ts',
|
|
1046
|
+
'src/guardrails/OWASPDetector.ts',
|
|
1047
|
+
'src/workflow/gates/GateSystem.ts',
|
|
1048
|
+
'src/workflow/ReviewAnalyzer.ts',
|
|
1049
|
+
'src/workflow/SecurityAudit.ts',
|
|
1050
|
+
].some(ruleSource => path.endsWith(ruleSource));
|
|
1051
|
+
}
|
|
997
1052
|
function updateTemplateLiteralState(line, currentlyInside) {
|
|
998
1053
|
let inside = currentlyInside;
|
|
999
1054
|
let escaped = false;
|