@neurcode-ai/cli 0.9.65 → 0.9.66
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/dist/commands/bootstrap-policy.d.ts +29 -0
- package/dist/commands/bootstrap-policy.d.ts.map +1 -0
- package/dist/commands/bootstrap-policy.js +334 -0
- package/dist/commands/bootstrap-policy.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +82 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/quickstart.d.ts +21 -0
- package/dist/commands/quickstart.d.ts.map +1 -0
- package/dist/commands/quickstart.js +178 -0
- package/dist/commands/quickstart.js.map +1 -0
- package/dist/commands/remediate-export.d.ts +31 -0
- package/dist/commands/remediate-export.d.ts.map +1 -0
- package/dist/commands/remediate-export.js +283 -0
- package/dist/commands/remediate-export.js.map +1 -0
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +106 -10
- package/dist/commands/verify.js.map +1 -1
- package/dist/governance/canonical-invariants.d.ts +88 -0
- package/dist/governance/canonical-invariants.d.ts.map +1 -0
- package/dist/governance/canonical-invariants.js +197 -0
- package/dist/governance/canonical-invariants.js.map +1 -0
- package/dist/governance/canonical-ordering.d.ts +76 -0
- package/dist/governance/canonical-ordering.d.ts.map +1 -0
- package/dist/governance/canonical-ordering.js +189 -0
- package/dist/governance/canonical-ordering.js.map +1 -0
- package/dist/governance/canonical-pipeline.d.ts +7 -0
- package/dist/governance/canonical-pipeline.d.ts.map +1 -1
- package/dist/governance/canonical-pipeline.js +184 -16
- package/dist/governance/canonical-pipeline.js.map +1 -1
- package/dist/governance/diff-line-provenance.d.ts +59 -0
- package/dist/governance/diff-line-provenance.d.ts.map +1 -0
- package/dist/governance/diff-line-provenance.js +118 -0
- package/dist/governance/diff-line-provenance.js.map +1 -0
- package/dist/governance/pilot-readiness.d.ts +34 -0
- package/dist/governance/pilot-readiness.d.ts.map +1 -0
- package/dist/governance/pilot-readiness.js +226 -0
- package/dist/governance/pilot-readiness.js.map +1 -0
- package/dist/governance/policy-parity-validator.d.ts +62 -0
- package/dist/governance/policy-parity-validator.d.ts.map +1 -0
- package/dist/governance/policy-parity-validator.js +137 -0
- package/dist/governance/policy-parity-validator.js.map +1 -0
- package/dist/governance/remediation-boundary.d.ts +55 -0
- package/dist/governance/remediation-boundary.d.ts.map +1 -0
- package/dist/governance/remediation-boundary.js +120 -0
- package/dist/governance/remediation-boundary.js.map +1 -0
- package/dist/governance/structural-cache.d.ts +103 -0
- package/dist/governance/structural-cache.d.ts.map +1 -0
- package/dist/governance/structural-cache.js +240 -0
- package/dist/governance/structural-cache.js.map +1 -0
- package/dist/governance/structural-on-diff.d.ts +22 -2
- package/dist/governance/structural-on-diff.d.ts.map +1 -1
- package/dist/governance/structural-on-diff.js +36 -4
- package/dist/governance/structural-on-diff.js.map +1 -1
- package/dist/governance/structural-policy-merge.d.ts +8 -0
- package/dist/governance/structural-policy-merge.d.ts.map +1 -1
- package/dist/governance/structural-policy-merge.js +7 -0
- package/dist/governance/structural-policy-merge.js.map +1 -1
- package/dist/governance/verify-runtime-guard.d.ts +99 -0
- package/dist/governance/verify-runtime-guard.d.ts.map +1 -0
- package/dist/governance/verify-runtime-guard.js +129 -0
- package/dist/governance/verify-runtime-guard.js.map +1 -0
- package/dist/index.js +50 -14
- package/dist/index.js.map +1 -1
- package/dist/intent-engine/repo-classifier.d.ts +64 -0
- package/dist/intent-engine/repo-classifier.d.ts.map +1 -0
- package/dist/intent-engine/repo-classifier.js +178 -0
- package/dist/intent-engine/repo-classifier.js.map +1 -0
- package/dist/structural-rules/index.d.ts +4 -0
- package/dist/structural-rules/index.d.ts.map +1 -1
- package/dist/structural-rules/index.js +18 -1
- package/dist/structural-rules/index.js.map +1 -1
- package/dist/structural-rules/python/PY003-broad-except-clause.d.ts +21 -0
- package/dist/structural-rules/python/PY003-broad-except-clause.d.ts.map +1 -1
- package/dist/structural-rules/python/PY003-broad-except-clause.js +212 -21
- package/dist/structural-rules/python/PY003-broad-except-clause.js.map +1 -1
- package/dist/structural-rules/python/PY011-thread-lifecycle.d.ts +11 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.d.ts.map +1 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.js +97 -0
- package/dist/structural-rules/python/PY011-thread-lifecycle.js.map +1 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.d.ts +11 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.d.ts.map +1 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.js +83 -0
- package/dist/structural-rules/python/PY012-asyncio-run-misuse.js.map +1 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.d.ts +11 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.d.ts.map +1 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.js +73 -0
- package/dist/structural-rules/python/PY013-mutable-default-arg.js.map +1 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.d.ts +11 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.d.ts.map +1 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.js +115 -0
- package/dist/structural-rules/python/PY014-fixed-sleep-retry.js.map +1 -0
- package/dist/structural-rules/types.d.ts +12 -0
- package/dist/structural-rules/types.d.ts.map +1 -1
- package/dist/utils/verify-runtime-stability.d.ts +142 -0
- package/dist/utils/verify-runtime-stability.d.ts.map +1 -0
- package/dist/utils/verify-runtime-stability.js +230 -0
- package/dist/utils/verify-runtime-stability.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pilot Readiness Validator (Phase 6 — Pilot Readiness Hardening)
|
|
4
|
+
*
|
|
5
|
+
* Checks that a repository meets all prerequisites for a reliable Neurcode
|
|
6
|
+
* onboarding. Designed to be runnable in under 10 seconds with no external
|
|
7
|
+
* network calls.
|
|
8
|
+
*
|
|
9
|
+
* Usage: runPilotReadinessCheck(projectRoot) → PilotReadinessReport
|
|
10
|
+
*
|
|
11
|
+
* Returns:
|
|
12
|
+
* ready: true if all blockers pass (warnings are non-blocking)
|
|
13
|
+
* blockers: list of hard failures that prevent governance from running
|
|
14
|
+
* warnings: list of soft issues that degrade experience but don't block
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.runPilotReadinessCheck = runPilotReadinessCheck;
|
|
18
|
+
const fs_1 = require("fs");
|
|
19
|
+
const path_1 = require("path");
|
|
20
|
+
const child_process_1 = require("child_process");
|
|
21
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
22
|
+
function check(name, fn) {
|
|
23
|
+
try {
|
|
24
|
+
const result = fn();
|
|
25
|
+
return { name, ...result };
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
return {
|
|
29
|
+
name,
|
|
30
|
+
status: 'fail',
|
|
31
|
+
message: `Check threw unexpectedly: ${e instanceof Error ? e.message : String(e)}`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function nodeVersion() {
|
|
36
|
+
const v = process.version; // e.g. 'v18.12.0'
|
|
37
|
+
return parseInt(v.slice(1).split('.')[0] ?? '0', 10);
|
|
38
|
+
}
|
|
39
|
+
// ── Individual checks ─────────────────────────────────────────────────────────
|
|
40
|
+
function checkGitAvailable() {
|
|
41
|
+
try {
|
|
42
|
+
(0, child_process_1.execSync)('git --version', { stdio: 'ignore', timeout: 3000 });
|
|
43
|
+
return { status: 'pass', message: 'git is available.' };
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return { status: 'fail', message: 'git is not available in PATH. Neurcode requires git to compute diffs.' };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function checkNodeVersion() {
|
|
50
|
+
const major = nodeVersion();
|
|
51
|
+
if (major >= 20)
|
|
52
|
+
return { status: 'pass', message: `Node.js v${major} (≥20 recommended).` };
|
|
53
|
+
if (major >= 18)
|
|
54
|
+
return { status: 'pass', message: `Node.js v${major} (supported; v20+ recommended for best performance).` };
|
|
55
|
+
return { status: 'fail', message: `Node.js v${major} is below minimum requirement (18). Upgrade to Node.js 18 or later.` };
|
|
56
|
+
}
|
|
57
|
+
function checkNeurcodeDir(projectRoot) {
|
|
58
|
+
const dir = (0, path_1.join)(projectRoot, '.neurcode');
|
|
59
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
60
|
+
// Not existing is fine — it will be created on first run
|
|
61
|
+
// But check that the parent directory is writable
|
|
62
|
+
try {
|
|
63
|
+
(0, fs_1.accessSync)(projectRoot, fs_1.constants.W_OK);
|
|
64
|
+
return { status: 'pass', message: '.neurcode/ does not exist yet (will be created on first verify run). Project root is writable.' };
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return { status: 'fail', message: `Project root '${projectRoot}' is not writable. Cannot create .neurcode/ directory.` };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
(0, fs_1.accessSync)(dir, fs_1.constants.W_OK);
|
|
72
|
+
return { status: 'pass', message: '.neurcode/ directory exists and is writable.' };
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return { status: 'fail', message: '.neurcode/ directory exists but is not writable. Check file permissions.' };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function checkPolicyLock(projectRoot) {
|
|
79
|
+
const lockPath = (0, path_1.join)(projectRoot, '.neurcode', 'neurcode.policy.lock.json');
|
|
80
|
+
if (!(0, fs_1.existsSync)(lockPath)) {
|
|
81
|
+
return {
|
|
82
|
+
status: 'warn',
|
|
83
|
+
message: 'Policy lock file (neurcode.policy.lock.json) not found. Run `neurcode policy bootstrap` to create it.',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const raw = (0, fs_1.readFileSync)(lockPath, 'utf-8');
|
|
88
|
+
const parsed = JSON.parse(raw);
|
|
89
|
+
if (typeof parsed === 'object' && parsed !== null) {
|
|
90
|
+
return { status: 'pass', message: 'Policy lock file exists and is valid JSON.' };
|
|
91
|
+
}
|
|
92
|
+
return { status: 'warn', message: 'Policy lock file exists but content is not a valid JSON object.' };
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return { status: 'fail', message: 'Policy lock file exists but is corrupt (invalid JSON). Delete and re-run `neurcode policy bootstrap`.' };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function checkCacheHealth(projectRoot) {
|
|
99
|
+
const cachePath = (0, path_1.join)(projectRoot, '.neurcode', 'structural-cache.json');
|
|
100
|
+
if (!(0, fs_1.existsSync)(cachePath)) {
|
|
101
|
+
return { status: 'pass', message: 'No structural cache found (cold start — normal for first run).' };
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const raw = (0, fs_1.readFileSync)(cachePath, 'utf-8');
|
|
105
|
+
const parsed = JSON.parse(raw);
|
|
106
|
+
if (typeof parsed === 'object' &&
|
|
107
|
+
parsed !== null &&
|
|
108
|
+
typeof parsed.version === 'number' &&
|
|
109
|
+
typeof parsed.entries === 'object') {
|
|
110
|
+
const entryCount = Object.keys(parsed.entries).length;
|
|
111
|
+
return { status: 'pass', message: `Structural cache exists and is valid (${entryCount} entries).` };
|
|
112
|
+
}
|
|
113
|
+
return { status: 'warn', message: 'Structural cache exists but has unexpected format. It will be regenerated on next verify run.' };
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return { status: 'warn', message: 'Structural cache file is corrupt. It will be regenerated on next verify run.' };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function checkRepoCompatibility(projectRoot) {
|
|
120
|
+
// Detect potentially unsupported repo configurations
|
|
121
|
+
const cargoToml = (0, path_1.join)(projectRoot, 'Cargo.toml');
|
|
122
|
+
const goMod = (0, path_1.join)(projectRoot, 'go.mod');
|
|
123
|
+
const packageJson = (0, path_1.join)(projectRoot, 'package.json');
|
|
124
|
+
const requirementsTxt = (0, path_1.join)(projectRoot, 'requirements.txt');
|
|
125
|
+
const pyprojectToml = (0, path_1.join)(projectRoot, 'pyproject.toml');
|
|
126
|
+
const pomXml = (0, path_1.join)(projectRoot, 'pom.xml');
|
|
127
|
+
const detected = [];
|
|
128
|
+
if ((0, fs_1.existsSync)(packageJson))
|
|
129
|
+
detected.push('Node.js/TypeScript');
|
|
130
|
+
if ((0, fs_1.existsSync)(requirementsTxt) || (0, fs_1.existsSync)(pyprojectToml))
|
|
131
|
+
detected.push('Python');
|
|
132
|
+
if ((0, fs_1.existsSync)(goMod))
|
|
133
|
+
detected.push('Go');
|
|
134
|
+
if ((0, fs_1.existsSync)(pomXml))
|
|
135
|
+
detected.push('Java/Maven');
|
|
136
|
+
if ((0, fs_1.existsSync)(cargoToml))
|
|
137
|
+
detected.push('Rust');
|
|
138
|
+
if (detected.length === 0) {
|
|
139
|
+
return {
|
|
140
|
+
status: 'warn',
|
|
141
|
+
message: 'No recognized dependency manifest found (package.json, requirements.txt, go.mod, pom.xml). ' +
|
|
142
|
+
'Repo may be unsupported. Structural rules will run in degraded mode.',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if ((0, fs_1.existsSync)(cargoToml) && detected.length === 1) {
|
|
146
|
+
return {
|
|
147
|
+
status: 'warn',
|
|
148
|
+
message: 'Pure Rust repository detected. Structural rules currently support TypeScript, JavaScript, and Python. ' +
|
|
149
|
+
'Policy engine will still run; structural analysis will be limited.',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
status: 'pass',
|
|
154
|
+
message: `Detected ecosystem(s): ${detected.join(', ')}. Structural rules are supported.`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function checkGitRepo(projectRoot) {
|
|
158
|
+
const gitDir = (0, path_1.join)(projectRoot, '.git');
|
|
159
|
+
if (!(0, fs_1.existsSync)(gitDir)) {
|
|
160
|
+
return {
|
|
161
|
+
status: 'fail',
|
|
162
|
+
message: 'Not a git repository (no .git directory found). Neurcode requires git history to compute diffs.',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return { status: 'pass', message: 'Git repository detected.' };
|
|
166
|
+
}
|
|
167
|
+
function checkActivePlan(projectRoot) {
|
|
168
|
+
// Check for a plan state file — existence indicates a plan is linked
|
|
169
|
+
const stateFile = (0, path_1.join)(projectRoot, '.neurcode', 'state.json');
|
|
170
|
+
if (!(0, fs_1.existsSync)(stateFile)) {
|
|
171
|
+
return {
|
|
172
|
+
status: 'warn',
|
|
173
|
+
message: 'No Neurcode state file found. Run `neurcode plan` to set an intent before verifying. ' +
|
|
174
|
+
'Without a plan, verify runs in advisory-only mode.',
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const raw = (0, fs_1.readFileSync)(stateFile, 'utf-8');
|
|
179
|
+
const state = JSON.parse(raw);
|
|
180
|
+
const planId = state.activePlanId ?? state.planId;
|
|
181
|
+
if (planId && typeof planId === 'string') {
|
|
182
|
+
return { status: 'pass', message: `Active plan detected: ${planId.slice(0, 16)}...` };
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
status: 'warn',
|
|
186
|
+
message: 'State file found but no active plan linked. Run `neurcode plan` to set intent.',
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return { status: 'warn', message: 'State file is unreadable. Run `neurcode plan` to re-link a plan.' };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// ── Main entry point ──────────────────────────────────────────────────────────
|
|
194
|
+
/**
|
|
195
|
+
* Run all pilot readiness checks for a repository.
|
|
196
|
+
*
|
|
197
|
+
* @param projectRoot Absolute path to the project root
|
|
198
|
+
* @returns PilotReadinessReport with ready flag, blockers, warnings, and per-check results
|
|
199
|
+
*/
|
|
200
|
+
function runPilotReadinessCheck(projectRoot) {
|
|
201
|
+
const startMs = Date.now();
|
|
202
|
+
const checks = [
|
|
203
|
+
check('git-available', () => checkGitAvailable()),
|
|
204
|
+
check('git-repository', () => checkGitRepo(projectRoot)),
|
|
205
|
+
check('node-version', () => checkNodeVersion()),
|
|
206
|
+
check('neurcode-dir', () => checkNeurcodeDir(projectRoot)),
|
|
207
|
+
check('repo-compatibility', () => checkRepoCompatibility(projectRoot)),
|
|
208
|
+
check('policy-lock', () => checkPolicyLock(projectRoot)),
|
|
209
|
+
check('cache-health', () => checkCacheHealth(projectRoot)),
|
|
210
|
+
check('active-plan', () => checkActivePlan(projectRoot)),
|
|
211
|
+
];
|
|
212
|
+
const blockers = checks
|
|
213
|
+
.filter(c => c.status === 'fail')
|
|
214
|
+
.map(c => `[${c.name}] ${c.message}`);
|
|
215
|
+
const warnings = checks
|
|
216
|
+
.filter(c => c.status === 'warn')
|
|
217
|
+
.map(c => `[${c.name}] ${c.message}`);
|
|
218
|
+
return {
|
|
219
|
+
ready: blockers.length === 0,
|
|
220
|
+
blockers,
|
|
221
|
+
warnings,
|
|
222
|
+
checks,
|
|
223
|
+
durationMs: Date.now() - startMs,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=pilot-readiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pilot-readiness.js","sourceRoot":"","sources":["../../src/governance/pilot-readiness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy Enforcement Parity Validator
|
|
3
|
+
*
|
|
4
|
+
* Closes the governance theatre gap: a policy can appear in policy.yml
|
|
5
|
+
* claiming "deterministic" enforcement, but have zero structural rule
|
|
6
|
+
* implementation. This validator surfaces those mismatches explicitly.
|
|
7
|
+
*
|
|
8
|
+
* Benchmark finding (Apache Airflow, 2026-05-12):
|
|
9
|
+
* 7 of 15 policies were unenforced. Enterprise teams believed those
|
|
10
|
+
* policies were being checked. They were not.
|
|
11
|
+
*
|
|
12
|
+
* This module is called from `neurcode verify --policy-only` to emit
|
|
13
|
+
* GOV_PARITY_MISMATCH advisory findings for every enforcement gap.
|
|
14
|
+
*/
|
|
15
|
+
export type EnforcementType = 'deterministic' | 'advisory' | 'semantic' | 'none';
|
|
16
|
+
export interface PolicyParityEntry {
|
|
17
|
+
ruleId: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
enforcementType: EnforcementType;
|
|
20
|
+
hasStructuralImpl: boolean;
|
|
21
|
+
hasPolicyEngineImpl: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface PolicyParityReport {
|
|
24
|
+
totalPolicies: number;
|
|
25
|
+
deterministicCount: number;
|
|
26
|
+
advisoryCount: number;
|
|
27
|
+
semanticCount: number;
|
|
28
|
+
noneCount: number;
|
|
29
|
+
/** Percentage of policies with deterministic structural enforcement (0-100) */
|
|
30
|
+
coveragePct: number;
|
|
31
|
+
/** Policies claiming deterministic but with no registered implementation */
|
|
32
|
+
unenforced: string[];
|
|
33
|
+
/** All entries with full detail */
|
|
34
|
+
entries: PolicyParityEntry[];
|
|
35
|
+
}
|
|
36
|
+
export interface ParityMismatchFinding {
|
|
37
|
+
ruleId: string;
|
|
38
|
+
policyName?: string;
|
|
39
|
+
message: string;
|
|
40
|
+
severity: 'advisory';
|
|
41
|
+
governanceCode: 'GOV_PARITY_MISMATCH';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Validate enforcement parity between policy declarations and the structural rule engine.
|
|
45
|
+
*
|
|
46
|
+
* @param policyRules - Rules from the compiled/loaded policy (array of { id, name, enforcementType? })
|
|
47
|
+
* @param registeredStructuralRuleIds - Set of rule IDs currently registered in StructuralRuleEngine
|
|
48
|
+
* @returns PolicyParityReport + mismatch findings (one per unenforced deterministic policy)
|
|
49
|
+
*/
|
|
50
|
+
export declare function validatePolicyEnforcementParity(policyRules: Array<{
|
|
51
|
+
id: string;
|
|
52
|
+
name?: string;
|
|
53
|
+
enforcementType?: string;
|
|
54
|
+
}>, registeredStructuralRuleIds: Set<string>): {
|
|
55
|
+
report: PolicyParityReport;
|
|
56
|
+
findings: ParityMismatchFinding[];
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Generate a compact governance coverage summary string for CLI output.
|
|
60
|
+
*/
|
|
61
|
+
export declare function formatParityReport(report: PolicyParityReport): string;
|
|
62
|
+
//# sourceMappingURL=policy-parity-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-parity-validator.d.ts","sourceRoot":"","sources":["../../src/governance/policy-parity-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAEjF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,eAAe,CAAC;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mCAAmC;IACnC,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,UAAU,CAAC;IACrB,cAAc,EAAE,qBAAqB,CAAC;CACvC;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC7C,WAAW,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC3E,2BAA2B,EAAE,GAAG,CAAC,MAAM,CAAC,GACvC;IAAE,MAAM,EAAE,kBAAkB,CAAC;IAAC,QAAQ,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAsEnE;AA4BD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAWrE"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Policy Enforcement Parity Validator
|
|
4
|
+
*
|
|
5
|
+
* Closes the governance theatre gap: a policy can appear in policy.yml
|
|
6
|
+
* claiming "deterministic" enforcement, but have zero structural rule
|
|
7
|
+
* implementation. This validator surfaces those mismatches explicitly.
|
|
8
|
+
*
|
|
9
|
+
* Benchmark finding (Apache Airflow, 2026-05-12):
|
|
10
|
+
* 7 of 15 policies were unenforced. Enterprise teams believed those
|
|
11
|
+
* policies were being checked. They were not.
|
|
12
|
+
*
|
|
13
|
+
* This module is called from `neurcode verify --policy-only` to emit
|
|
14
|
+
* GOV_PARITY_MISMATCH advisory findings for every enforcement gap.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.validatePolicyEnforcementParity = validatePolicyEnforcementParity;
|
|
18
|
+
exports.formatParityReport = formatParityReport;
|
|
19
|
+
/**
|
|
20
|
+
* Validate enforcement parity between policy declarations and the structural rule engine.
|
|
21
|
+
*
|
|
22
|
+
* @param policyRules - Rules from the compiled/loaded policy (array of { id, name, enforcementType? })
|
|
23
|
+
* @param registeredStructuralRuleIds - Set of rule IDs currently registered in StructuralRuleEngine
|
|
24
|
+
* @returns PolicyParityReport + mismatch findings (one per unenforced deterministic policy)
|
|
25
|
+
*/
|
|
26
|
+
function validatePolicyEnforcementParity(policyRules, registeredStructuralRuleIds) {
|
|
27
|
+
const entries = [];
|
|
28
|
+
const findings = [];
|
|
29
|
+
let deterministicCount = 0;
|
|
30
|
+
let advisoryCount = 0;
|
|
31
|
+
let semanticCount = 0;
|
|
32
|
+
let noneCount = 0;
|
|
33
|
+
const unenforced = [];
|
|
34
|
+
for (const rule of policyRules) {
|
|
35
|
+
const rawType = rule.enforcementType ?? 'none';
|
|
36
|
+
const enforcementType = normalizeEnforcementType(rawType);
|
|
37
|
+
const hasStructuralImpl = registeredStructuralRuleIds.has(rule.id);
|
|
38
|
+
// Policy-engine rules (evaluated separately) — count as implemented if known
|
|
39
|
+
const hasPolicyEngineImpl = KNOWN_POLICY_ENGINE_RULES.has(rule.id);
|
|
40
|
+
entries.push({
|
|
41
|
+
ruleId: rule.id,
|
|
42
|
+
name: rule.name,
|
|
43
|
+
enforcementType,
|
|
44
|
+
hasStructuralImpl,
|
|
45
|
+
hasPolicyEngineImpl,
|
|
46
|
+
});
|
|
47
|
+
switch (enforcementType) {
|
|
48
|
+
case 'deterministic':
|
|
49
|
+
deterministicCount++;
|
|
50
|
+
break;
|
|
51
|
+
case 'advisory':
|
|
52
|
+
advisoryCount++;
|
|
53
|
+
break;
|
|
54
|
+
case 'semantic':
|
|
55
|
+
semanticCount++;
|
|
56
|
+
break;
|
|
57
|
+
case 'none':
|
|
58
|
+
noneCount++;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
// Emit a mismatch finding if a policy claims deterministic enforcement
|
|
62
|
+
// but has no matching rule implementation
|
|
63
|
+
if (enforcementType === 'deterministic' && !hasStructuralImpl && !hasPolicyEngineImpl) {
|
|
64
|
+
unenforced.push(rule.id);
|
|
65
|
+
findings.push({
|
|
66
|
+
ruleId: rule.id,
|
|
67
|
+
policyName: rule.name,
|
|
68
|
+
severity: 'advisory',
|
|
69
|
+
governanceCode: 'GOV_PARITY_MISMATCH',
|
|
70
|
+
message: `Policy "${rule.name ?? rule.id}" declares enforcementType: deterministic ` +
|
|
71
|
+
`but has no registered structural or policy-engine implementation. ` +
|
|
72
|
+
`This policy will NEVER produce a finding. ` +
|
|
73
|
+
`Either add a structural rule for ${rule.id}, change enforcementType to "none", ` +
|
|
74
|
+
`or remove the policy. ` +
|
|
75
|
+
`(Unenforced deterministic policies create false governance confidence.)`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const enforced = deterministicCount - unenforced.length;
|
|
80
|
+
const coveragePct = deterministicCount === 0
|
|
81
|
+
? 100 // no deterministic claims = 100% parity (vacuously true)
|
|
82
|
+
: Math.round((enforced / deterministicCount) * 100);
|
|
83
|
+
const report = {
|
|
84
|
+
totalPolicies: policyRules.length,
|
|
85
|
+
deterministicCount,
|
|
86
|
+
advisoryCount,
|
|
87
|
+
semanticCount,
|
|
88
|
+
noneCount,
|
|
89
|
+
coveragePct,
|
|
90
|
+
unenforced,
|
|
91
|
+
entries,
|
|
92
|
+
};
|
|
93
|
+
return { report, findings };
|
|
94
|
+
}
|
|
95
|
+
function normalizeEnforcementType(raw) {
|
|
96
|
+
const v = raw.toLowerCase().trim();
|
|
97
|
+
if (v === 'deterministic')
|
|
98
|
+
return 'deterministic';
|
|
99
|
+
if (v === 'advisory')
|
|
100
|
+
return 'advisory';
|
|
101
|
+
if (v === 'semantic')
|
|
102
|
+
return 'semantic';
|
|
103
|
+
return 'none';
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Known policy-engine rule IDs that are enforced via the policy YAML evaluator
|
|
107
|
+
* (not via the structural rule engine). These are counted as implemented.
|
|
108
|
+
*/
|
|
109
|
+
const KNOWN_POLICY_ENGINE_RULES = new Set([
|
|
110
|
+
'NO_HARDCODED_SECRETS',
|
|
111
|
+
'REQUIRE_RESOURCE_TAGGING',
|
|
112
|
+
'PY001_NO_BARE_EXCEPT',
|
|
113
|
+
'PY003_ASYNC_SAFETY',
|
|
114
|
+
'TS001_TYPED_BOUNDARIES',
|
|
115
|
+
'GOV001_REPLAY_INTEGRITY_REQUIRED',
|
|
116
|
+
'GOV002_SUPPRESSION_REQUIRES_JUSTIFICATION',
|
|
117
|
+
'potential-secret-default',
|
|
118
|
+
'potential-secret-high',
|
|
119
|
+
'require-signed-ai-logs',
|
|
120
|
+
'ai-change-log-integrity',
|
|
121
|
+
]);
|
|
122
|
+
/**
|
|
123
|
+
* Generate a compact governance coverage summary string for CLI output.
|
|
124
|
+
*/
|
|
125
|
+
function formatParityReport(report) {
|
|
126
|
+
const { totalPolicies, deterministicCount, advisoryCount, semanticCount, noneCount, coveragePct, unenforced } = report;
|
|
127
|
+
const lines = [
|
|
128
|
+
`Policy Enforcement Coverage: ${coveragePct}% (${deterministicCount - unenforced.length}/${deterministicCount} deterministic policies enforced)`,
|
|
129
|
+
` Total policies: ${totalPolicies} | Deterministic: ${deterministicCount} | Advisory: ${advisoryCount} | Semantic: ${semanticCount} | Unenforced: ${noneCount + unenforced.length}`,
|
|
130
|
+
];
|
|
131
|
+
if (unenforced.length > 0) {
|
|
132
|
+
lines.push(` ⚠ Unenforced deterministic policies: ${unenforced.join(', ')}`);
|
|
133
|
+
lines.push(` These policies appear in policy.yml as deterministic but will NEVER produce findings.`);
|
|
134
|
+
}
|
|
135
|
+
return lines.join('\n');
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=policy-parity-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-parity-validator.js","sourceRoot":"","sources":["../../src/governance/policy-parity-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remediation Boundary Enforcement (Phase 4)
|
|
3
|
+
*
|
|
4
|
+
* Validates that a remediation suggestion respects strict boundaries:
|
|
5
|
+
* - Same language as the finding
|
|
6
|
+
* - Same package/subsystem boundary (inferred from file path)
|
|
7
|
+
* - No cross-frontend/backend boundary crossings
|
|
8
|
+
*
|
|
9
|
+
* If no safe remediation can be proposed within these constraints, returns
|
|
10
|
+
* the sentinel string "No safe remediation suggestion available." which is
|
|
11
|
+
* preferable to misleading cross-boundary guidance.
|
|
12
|
+
*
|
|
13
|
+
* This is a deterministic, pure-function module — no I/O, no LLM.
|
|
14
|
+
*/
|
|
15
|
+
import type { RuleLanguage } from '../structural-rules/types';
|
|
16
|
+
export interface RemediationBoundaryInput {
|
|
17
|
+
/** The file path where the violation was found */
|
|
18
|
+
findingFilePath: string;
|
|
19
|
+
/** The language of the finding */
|
|
20
|
+
findingLanguage: RuleLanguage | string;
|
|
21
|
+
/** The proposed target file for the remediation */
|
|
22
|
+
targetFilePath: string;
|
|
23
|
+
/** The language the remediation targets (if known) */
|
|
24
|
+
targetLanguage?: RuleLanguage | string;
|
|
25
|
+
}
|
|
26
|
+
export interface BoundaryCheckResult {
|
|
27
|
+
allowed: boolean;
|
|
28
|
+
reason: string;
|
|
29
|
+
/** Sentinel value when no safe remediation is possible */
|
|
30
|
+
safeRemediationUnavailable?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Validate whether a remediation suggestion crosses acceptable boundaries.
|
|
34
|
+
*
|
|
35
|
+
* Enforcement rules (in priority order):
|
|
36
|
+
* 1. Language boundary: finding language must match target language
|
|
37
|
+
* Exception: typescript ↔ javascript is allowed (same ecosystem)
|
|
38
|
+
* 2. Frontend/backend boundary: must not cross unless explicitly linked
|
|
39
|
+
* 3. Infrastructure boundary: infra files cannot be remediation targets for
|
|
40
|
+
* application-layer findings
|
|
41
|
+
*/
|
|
42
|
+
export declare function validateRemediationBoundary(input: RemediationBoundaryInput): BoundaryCheckResult;
|
|
43
|
+
/**
|
|
44
|
+
* The sentinel string returned when no safe remediation is available.
|
|
45
|
+
* Consumers MUST check for this exact string and suppress remediation output.
|
|
46
|
+
*/
|
|
47
|
+
export declare const NO_SAFE_REMEDIATION: "No safe remediation suggestion available.";
|
|
48
|
+
/**
|
|
49
|
+
* Wrap a remediation string with boundary validation.
|
|
50
|
+
*
|
|
51
|
+
* Returns the original remediation if the boundary is safe, or the
|
|
52
|
+
* NO_SAFE_REMEDIATION sentinel if the boundary is violated.
|
|
53
|
+
*/
|
|
54
|
+
export declare function boundedRemediation(input: RemediationBoundaryInput, remediation: string): string;
|
|
55
|
+
//# sourceMappingURL=remediation-boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remediation-boundary.d.ts","sourceRoot":"","sources":["../../src/governance/remediation-boundary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAI9D,MAAM,WAAW,wBAAwB;IACvC,kDAAkD;IAClD,eAAe,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,eAAe,EAAE,YAAY,GAAG,MAAM,CAAC;IACvC,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,sDAAsD;IACtD,cAAc,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,wBAAwB,GAC9B,mBAAmB,CAgErB;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAG,2CAAoD,CAAC;AAExF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,wBAAwB,EAC/B,WAAW,EAAE,MAAM,GAClB,MAAM,CAIR"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Remediation Boundary Enforcement (Phase 4)
|
|
4
|
+
*
|
|
5
|
+
* Validates that a remediation suggestion respects strict boundaries:
|
|
6
|
+
* - Same language as the finding
|
|
7
|
+
* - Same package/subsystem boundary (inferred from file path)
|
|
8
|
+
* - No cross-frontend/backend boundary crossings
|
|
9
|
+
*
|
|
10
|
+
* If no safe remediation can be proposed within these constraints, returns
|
|
11
|
+
* the sentinel string "No safe remediation suggestion available." which is
|
|
12
|
+
* preferable to misleading cross-boundary guidance.
|
|
13
|
+
*
|
|
14
|
+
* This is a deterministic, pure-function module — no I/O, no LLM.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.NO_SAFE_REMEDIATION = void 0;
|
|
18
|
+
exports.validateRemediationBoundary = validateRemediationBoundary;
|
|
19
|
+
exports.boundedRemediation = boundedRemediation;
|
|
20
|
+
const FRONTEND_PATH_RE = /(?:^|\/)(?:web|frontend|client|ui|dashboard|pages?|components?|views?|screens?|app\/(?:page|layout))[/\\]/i;
|
|
21
|
+
const BACKEND_PATH_RE = /(?:^|\/)(?:api|services?|server|backend|controllers?|handlers?|routes?|domain)[/\\]/i;
|
|
22
|
+
const INFRA_PATH_RE = /(?:^|\/)(?:infra|k8s|terraform|docker|deploy|charts?)[/\\]/i;
|
|
23
|
+
const TEST_PATH_RE = /(?:^|\/)(?:__tests?__|tests?|spec|e2e)[/\\]|\.(?:test|spec)\.\w+$/i;
|
|
24
|
+
function classifySubsystem(filePath) {
|
|
25
|
+
const p = filePath.replace(/\\/g, '/');
|
|
26
|
+
if (TEST_PATH_RE.test(p))
|
|
27
|
+
return 'test';
|
|
28
|
+
if (INFRA_PATH_RE.test(p))
|
|
29
|
+
return 'infra';
|
|
30
|
+
if (FRONTEND_PATH_RE.test(p))
|
|
31
|
+
return 'frontend';
|
|
32
|
+
if (BACKEND_PATH_RE.test(p))
|
|
33
|
+
return 'backend';
|
|
34
|
+
return 'unknown';
|
|
35
|
+
}
|
|
36
|
+
// ── Language inference from file extension ────────────────────────────────────
|
|
37
|
+
function inferLanguageFromPath(filePath) {
|
|
38
|
+
if (/\.(ts|tsx)$/.test(filePath))
|
|
39
|
+
return 'typescript';
|
|
40
|
+
if (/\.(js|jsx|mjs|cjs)$/.test(filePath))
|
|
41
|
+
return 'javascript';
|
|
42
|
+
if (/\.py$/.test(filePath))
|
|
43
|
+
return 'python';
|
|
44
|
+
return 'unknown';
|
|
45
|
+
}
|
|
46
|
+
// ── Boundary validation ───────────────────────────────────────────────────────
|
|
47
|
+
/**
|
|
48
|
+
* Validate whether a remediation suggestion crosses acceptable boundaries.
|
|
49
|
+
*
|
|
50
|
+
* Enforcement rules (in priority order):
|
|
51
|
+
* 1. Language boundary: finding language must match target language
|
|
52
|
+
* Exception: typescript ↔ javascript is allowed (same ecosystem)
|
|
53
|
+
* 2. Frontend/backend boundary: must not cross unless explicitly linked
|
|
54
|
+
* 3. Infrastructure boundary: infra files cannot be remediation targets for
|
|
55
|
+
* application-layer findings
|
|
56
|
+
*/
|
|
57
|
+
function validateRemediationBoundary(input) {
|
|
58
|
+
const { findingFilePath, findingLanguage, targetFilePath, targetLanguage: explicitTargetLang, } = input;
|
|
59
|
+
const effectiveTargetLang = explicitTargetLang ?? inferLanguageFromPath(targetFilePath);
|
|
60
|
+
const findingSubsystem = classifySubsystem(findingFilePath);
|
|
61
|
+
const targetSubsystem = classifySubsystem(targetFilePath);
|
|
62
|
+
// ── Rule 1: Language boundary ──────────────────────────────────────────────
|
|
63
|
+
if (effectiveTargetLang !== 'unknown' &&
|
|
64
|
+
findingLanguage !== effectiveTargetLang) {
|
|
65
|
+
// Allow typescript ↔ javascript (same ecosystem, transpiled)
|
|
66
|
+
const tsJsCompat = (findingLanguage === 'typescript' && effectiveTargetLang === 'javascript') ||
|
|
67
|
+
(findingLanguage === 'javascript' && effectiveTargetLang === 'typescript');
|
|
68
|
+
if (!tsJsCompat) {
|
|
69
|
+
return {
|
|
70
|
+
allowed: false,
|
|
71
|
+
safeRemediationUnavailable: true,
|
|
72
|
+
reason: `Language boundary violation: finding is in '${findingLanguage}' but remediation ` +
|
|
73
|
+
`targets '${effectiveTargetLang}' file '${targetFilePath}'. ` +
|
|
74
|
+
'Cross-language remediation is not safe.',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// ── Rule 2: Frontend/backend boundary ─────────────────────────────────────
|
|
79
|
+
if ((findingSubsystem === 'frontend' && targetSubsystem === 'backend') ||
|
|
80
|
+
(findingSubsystem === 'backend' && targetSubsystem === 'frontend')) {
|
|
81
|
+
return {
|
|
82
|
+
allowed: false,
|
|
83
|
+
safeRemediationUnavailable: true,
|
|
84
|
+
reason: `Subsystem boundary violation: finding is in '${findingSubsystem}' ` +
|
|
85
|
+
`but remediation targets '${targetSubsystem}' file '${targetFilePath}'. ` +
|
|
86
|
+
'Cross-boundary remediation requires explicit architectural approval.',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// ── Rule 3: Infra boundary ─────────────────────────────────────────────────
|
|
90
|
+
if (targetSubsystem === 'infra' && findingSubsystem !== 'infra') {
|
|
91
|
+
return {
|
|
92
|
+
allowed: false,
|
|
93
|
+
safeRemediationUnavailable: true,
|
|
94
|
+
reason: `Infrastructure boundary violation: application-layer finding in '${findingFilePath}' ` +
|
|
95
|
+
`cannot be remediated by modifying infrastructure file '${targetFilePath}'.`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
allowed: true,
|
|
100
|
+
reason: 'Remediation is within safe boundaries.',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The sentinel string returned when no safe remediation is available.
|
|
105
|
+
* Consumers MUST check for this exact string and suppress remediation output.
|
|
106
|
+
*/
|
|
107
|
+
exports.NO_SAFE_REMEDIATION = 'No safe remediation suggestion available.';
|
|
108
|
+
/**
|
|
109
|
+
* Wrap a remediation string with boundary validation.
|
|
110
|
+
*
|
|
111
|
+
* Returns the original remediation if the boundary is safe, or the
|
|
112
|
+
* NO_SAFE_REMEDIATION sentinel if the boundary is violated.
|
|
113
|
+
*/
|
|
114
|
+
function boundedRemediation(input, remediation) {
|
|
115
|
+
const result = validateRemediationBoundary(input);
|
|
116
|
+
if (!result.allowed)
|
|
117
|
+
return exports.NO_SAFE_REMEDIATION;
|
|
118
|
+
return remediation;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=remediation-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remediation-boundary.js","sourceRoot":"","sources":["../../src/governance/remediation-boundary.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AA+DH,kEAkEC;AAcD,gDAOC;AA1HD,MAAM,gBAAgB,GAAG,4GAA4G,CAAC;AACtI,MAAM,eAAe,GAAI,sFAAsF,CAAC;AAChH,MAAM,aAAa,GAAM,6DAA6D,CAAC;AACvF,MAAM,YAAY,GAAO,oEAAoE,CAAC;AAE9F,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IACxC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC;IAC1C,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC;IAChD,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,iFAAiF;AAEjF,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC;IACtD,IAAI,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC;IAC9D,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;GASG;AACH,SAAgB,2BAA2B,CACzC,KAA+B;IAE/B,MAAM,EACJ,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EAAE,kBAAkB,GACnC,GAAG,KAAK,CAAC;IAEV,MAAM,mBAAmB,GAAG,kBAAkB,IAAI,qBAAqB,CAAC,cAAc,CAAC,CAAC;IACxF,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,eAAe,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAI,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAE3D,8EAA8E;IAC9E,IACE,mBAAmB,KAAK,SAAS;QACjC,eAAe,KAAK,mBAAmB,EACvC,CAAC;QACD,6DAA6D;QAC7D,MAAM,UAAU,GACd,CAAC,eAAe,KAAK,YAAY,IAAI,mBAAmB,KAAK,YAAY,CAAC;YAC1E,CAAC,eAAe,KAAK,YAAY,IAAI,mBAAmB,KAAK,YAAY,CAAC,CAAC;QAE7E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,0BAA0B,EAAE,IAAI;gBAChC,MAAM,EACJ,+CAA+C,eAAe,oBAAoB;oBAClF,YAAY,mBAAmB,WAAW,cAAc,KAAK;oBAC7D,yCAAyC;aAC5C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,IACE,CAAC,gBAAgB,KAAK,UAAU,IAAI,eAAe,KAAK,SAAS,CAAC;QAClE,CAAC,gBAAgB,KAAK,SAAS,IAAK,eAAe,KAAK,UAAU,CAAC,EACnE,CAAC;QACD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,0BAA0B,EAAE,IAAI;YAChC,MAAM,EACJ,gDAAgD,gBAAgB,IAAI;gBACpE,4BAA4B,eAAe,WAAW,cAAc,KAAK;gBACzE,sEAAsE;SACzE,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,IAAI,eAAe,KAAK,OAAO,IAAI,gBAAgB,KAAK,OAAO,EAAE,CAAC;QAChE,OAAO;YACL,OAAO,EAAE,KAAK;YACd,0BAA0B,EAAE,IAAI;YAChC,MAAM,EACJ,oEAAoE,eAAe,IAAI;gBACvF,0DAA0D,cAAc,IAAI;SAC/E,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,wCAAwC;KACjD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACU,QAAA,mBAAmB,GAAG,2CAAoD,CAAC;AAExF;;;;;GAKG;AACH,SAAgB,kBAAkB,CAChC,KAA+B,EAC/B,WAAmB;IAEnB,MAAM,MAAM,GAAG,2BAA2B,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,2BAAmB,CAAC;IAChD,OAAO,WAAW,CAAC;AACrB,CAAC"}
|