pumuki 6.3.289 → 6.3.291
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/VERSION +1 -1
- package/integrations/git/runPlatformGate.ts +116 -2
- package/package.json +1 -1
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.3.
|
|
1
|
+
6.3.291
|
|
@@ -108,12 +108,123 @@ const hasActionableFindingLocation = (finding: Finding): boolean => {
|
|
|
108
108
|
);
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
+
const normalizeFindingLines = (lines: Finding['lines']): ReadonlyArray<number> => {
|
|
112
|
+
if (typeof lines === 'number') {
|
|
113
|
+
return Number.isFinite(lines) && lines > 0 ? [Math.trunc(lines)] : [];
|
|
114
|
+
}
|
|
115
|
+
if (Array.isArray(lines)) {
|
|
116
|
+
return [...new Set(lines.filter((line) => Number.isFinite(line) && line > 0).map((line) => Math.trunc(line)))].sort(
|
|
117
|
+
(left, right) => left - right
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (typeof lines === 'string') {
|
|
121
|
+
return [...new Set(
|
|
122
|
+
lines
|
|
123
|
+
.split(/[^0-9]+/)
|
|
124
|
+
.map((line) => Number.parseInt(line, 10))
|
|
125
|
+
.filter((line) => Number.isFinite(line) && line > 0)
|
|
126
|
+
)].sort((left, right) => left - right);
|
|
127
|
+
}
|
|
128
|
+
return [];
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const parseChangedLinesByPathFromUnifiedDiff = (diff: string): Map<string, Set<number>> => {
|
|
132
|
+
const changedLinesByPath = new Map<string, Set<number>>();
|
|
133
|
+
let currentPath: string | undefined;
|
|
134
|
+
|
|
135
|
+
for (const rawLine of diff.split('\n')) {
|
|
136
|
+
if (rawLine.startsWith('+++ b/')) {
|
|
137
|
+
const nextPath = rawLine.slice('+++ b/'.length).trim();
|
|
138
|
+
currentPath = nextPath.length > 0 && nextPath !== '/dev/null' ? toNormalizedPath(nextPath) : undefined;
|
|
139
|
+
if (currentPath && !changedLinesByPath.has(currentPath)) {
|
|
140
|
+
changedLinesByPath.set(currentPath, new Set<number>());
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!currentPath || !rawLine.startsWith('@@')) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const hunkMatch = rawLine.match(/\+(\d+)(?:,(\d+))?/);
|
|
150
|
+
if (!hunkMatch) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const startLine = Number.parseInt(hunkMatch[1] ?? '', 10);
|
|
154
|
+
const lineCount = hunkMatch[2] === undefined ? 1 : Number.parseInt(hunkMatch[2], 10);
|
|
155
|
+
if (!Number.isFinite(startLine) || startLine <= 0 || !Number.isFinite(lineCount)) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const changedLines = changedLinesByPath.get(currentPath) ?? new Set<number>();
|
|
159
|
+
for (let offset = 0; offset < Math.max(0, lineCount); offset += 1) {
|
|
160
|
+
changedLines.add(startLine + offset);
|
|
161
|
+
}
|
|
162
|
+
changedLinesByPath.set(currentPath, changedLines);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return changedLinesByPath;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const collectStagedChangedLinesByPath = (
|
|
169
|
+
git: IGitService,
|
|
170
|
+
repoRoot: string
|
|
171
|
+
): Map<string, Set<number>> => {
|
|
172
|
+
try {
|
|
173
|
+
return parseChangedLinesByPathFromUnifiedDiff(
|
|
174
|
+
git.runGit(['diff', '--cached', '--unified=0', '--no-ext-diff'], repoRoot)
|
|
175
|
+
);
|
|
176
|
+
} catch {
|
|
177
|
+
return new Map<string, Set<number>>();
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const isFindingOutsideChangedLines = (
|
|
182
|
+
finding: Finding,
|
|
183
|
+
changedLinesByPath: ReadonlyMap<string, ReadonlySet<number>>
|
|
184
|
+
): boolean => {
|
|
185
|
+
if (!finding.filePath) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
const changedLines = changedLinesByPath.get(toNormalizedPath(finding.filePath));
|
|
189
|
+
if (!changedLines || changedLines.size === 0) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
const findingLines = normalizeFindingLines(finding.lines);
|
|
193
|
+
if (findingLines.length === 0) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
return findingLines.every((line) => !changedLines.has(line));
|
|
197
|
+
};
|
|
198
|
+
|
|
111
199
|
const normalizeScopedRuleEngineFindings = (params: {
|
|
112
200
|
findings: ReadonlyArray<Finding>;
|
|
113
201
|
scope: GateScope;
|
|
202
|
+
stage: GatePolicy['stage'];
|
|
203
|
+
changedLinesByPath: ReadonlyMap<string, ReadonlySet<number>>;
|
|
114
204
|
}): ReadonlyArray<Finding> => {
|
|
115
|
-
|
|
116
|
-
|
|
205
|
+
if (
|
|
206
|
+
(params.scope.kind !== 'staged' && params.scope.kind !== 'repoAndStaged') ||
|
|
207
|
+
(params.stage !== 'PRE_WRITE' && params.stage !== 'PRE_COMMIT')
|
|
208
|
+
) {
|
|
209
|
+
return params.findings;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return params.findings.map((finding) => {
|
|
213
|
+
if (!isAstRuleFinding(finding) || !isFindingOutsideChangedLines(finding, params.changedLinesByPath)) {
|
|
214
|
+
return finding;
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
...finding,
|
|
218
|
+
blocking: false,
|
|
219
|
+
severity: 'INFO',
|
|
220
|
+
message:
|
|
221
|
+
`${finding.message} ` +
|
|
222
|
+
'Baseline brownfield outside the staged diff; tracked as advisory for this atomic slice.',
|
|
223
|
+
expected_fix:
|
|
224
|
+
finding.expected_fix ??
|
|
225
|
+
'Plan a dedicated brownfield remediation slice for this pre-existing finding.',
|
|
226
|
+
};
|
|
227
|
+
});
|
|
117
228
|
};
|
|
118
229
|
|
|
119
230
|
const buildDefaultMemoryShadowRecommendation = (params: {
|
|
@@ -988,6 +1099,7 @@ export async function runPlatformGate(params: {
|
|
|
988
1099
|
gateScopePathPrefixes
|
|
989
1100
|
);
|
|
990
1101
|
const stagedPaths = collectStagedPaths(git, repoRoot);
|
|
1102
|
+
const stagedChangedLinesByPath = collectStagedChangedLinesByPath(git, repoRoot);
|
|
991
1103
|
const factsForPlatformEvaluation = shouldAugmentStagedSkillsContractFactsWithRepoFacts({
|
|
992
1104
|
scope: params.scope,
|
|
993
1105
|
facts,
|
|
@@ -1039,6 +1151,8 @@ export async function runPlatformGate(params: {
|
|
|
1039
1151
|
const scopedRuleEngineFindings = normalizeScopedRuleEngineFindings({
|
|
1040
1152
|
findings: ruleEngineFindings,
|
|
1041
1153
|
scope: params.scope,
|
|
1154
|
+
stage: params.policy.stage,
|
|
1155
|
+
changedLinesByPath: stagedChangedLinesByPath,
|
|
1042
1156
|
});
|
|
1043
1157
|
const findings = [...aiGateRepoPolicyFindings, ...scopedRuleEngineFindings];
|
|
1044
1158
|
const evaluationMetrics: SnapshotEvaluationMetrics = coverage
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.291",
|
|
4
4
|
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|