pumuki 6.3.293 → 6.3.295
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/VERSION +1 -1
- package/core/facts/detectors/text/ios.test.ts +65 -0
- package/core/facts/detectors/text/ios.ts +66 -6
- package/core/facts/detectors/typescript/index.test.ts +1115 -94
- package/core/facts/detectors/typescript/index.ts +653 -1
- package/core/facts/extractHeuristicFacts.ts +33 -2
- package/core/rules/presets/heuristics/ios.test.ts +11 -1
- package/core/rules/presets/heuristics/ios.ts +36 -0
- package/core/rules/presets/heuristics/typescript.test.ts +73 -1
- package/core/rules/presets/heuristics/typescript.ts +264 -0
- package/integrations/config/skillsDetectorRegistry.ts +90 -0
- package/integrations/git/runPlatformGate.ts +41 -3
- package/package.json +1 -1
|
@@ -175,6 +175,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
175
175
|
'ios.error.empty-catch',
|
|
176
176
|
['heuristics.ios.error.empty-catch.ast']
|
|
177
177
|
),
|
|
178
|
+
'skills.ios.guideline.ios.error-handling-custom-networkerror-enum': heuristicDetector(
|
|
179
|
+
'ios.error.typed-error-enum',
|
|
180
|
+
['heuristics.ios.error.nserror-throw.ast']
|
|
181
|
+
),
|
|
182
|
+
'skills.ios.guideline.ios.error-handling-global-custom-error-enum': heuristicDetector(
|
|
183
|
+
'ios.error.typed-error-enum',
|
|
184
|
+
['heuristics.ios.error.nserror-throw.ast']
|
|
185
|
+
),
|
|
178
186
|
'skills.ios.guideline.ios.no-loggear-pii-tokens-emails-ids-sensibles': heuristicDetector(
|
|
179
187
|
'ios.logging.sensitive-data',
|
|
180
188
|
['heuristics.ios.logging.sensitive-data.ast']
|
|
@@ -364,6 +372,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
364
372
|
heuristicDetector('ios.swiftui.environment-system-values-no-swinject', [
|
|
365
373
|
'heuristics.ios.architecture.swinject.ast',
|
|
366
374
|
]),
|
|
375
|
+
'skills.ios.guideline.ios.dependencies-en-package-swift-versiones-especi-ficas':
|
|
376
|
+
heuristicDetector('ios.dependencies.swiftpm-branch-dependency', [
|
|
377
|
+
'heuristics.ios.dependencies.swiftpm-branch-dependency.ast',
|
|
378
|
+
]),
|
|
367
379
|
'skills.ios.no-unchecked-sendable': heuristicDetector('ios.unchecked-sendable', [
|
|
368
380
|
'heuristics.ios.unchecked-sendable.ast',
|
|
369
381
|
]),
|
|
@@ -397,6 +409,8 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
397
409
|
'skills.ios.no-assume-isolated': heuristicDetector('ios.assume-isolated', [
|
|
398
410
|
'heuristics.ios.assume-isolated.ast',
|
|
399
411
|
]),
|
|
412
|
+
'skills.ios.guideline.ios.no-usar-mainactor-como-parche-justificar-el-aislamiento':
|
|
413
|
+
heuristicDetector('ios.assume-isolated', ['heuristics.ios.assume-isolated.ast']),
|
|
400
414
|
'skills.ios.no-observable-object': heuristicDetector('ios.observable-object', [
|
|
401
415
|
'heuristics.ios.observable-object.ast',
|
|
402
416
|
]),
|
|
@@ -781,6 +795,38 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
781
795
|
heuristicDetector('typescript.backend.persistence-mutation-without-audit-event', [
|
|
782
796
|
'heuristics.ts.backend.persistence-mutation-without-audit-event.ast',
|
|
783
797
|
]),
|
|
798
|
+
'skills.backend.guideline.backend.event-handlers-onevent-order-created': heuristicDetector(
|
|
799
|
+
'typescript.backend.event-handler-without-on-event',
|
|
800
|
+
['heuristics.ts.backend.event-handler-without-on-event.ast']
|
|
801
|
+
),
|
|
802
|
+
'skills.backend.guideline.backend.no-cachear-datos-sensibles-o-cifrar-antes-de-cachear':
|
|
803
|
+
heuristicDetector('typescript.backend.sensitive-cache-write', [
|
|
804
|
+
'heuristics.ts.backend.sensitive-cache-write.ast',
|
|
805
|
+
]),
|
|
806
|
+
'skills.backend.guideline.backend.refresh-tokens-no-solo-access-tokens':
|
|
807
|
+
heuristicDetector('typescript.backend.auth-response-without-refresh-token', [
|
|
808
|
+
'heuristics.ts.backend.auth-response-without-refresh-token.ast',
|
|
809
|
+
]),
|
|
810
|
+
'skills.backend.guideline.backend.no-defaults-en-produccio-n-fallar-si-falta-config-cri-tica':
|
|
811
|
+
heuristicDetector('typescript.backend.process-env-default-fallback', [
|
|
812
|
+
'heuristics.ts.backend.process-env-default-fallback.ast',
|
|
813
|
+
]),
|
|
814
|
+
'skills.backend.guideline.backend.correlation-ids-para-tracing-distribuido':
|
|
815
|
+
heuristicDetector('typescript.backend.log-without-context', [
|
|
816
|
+
'heuristics.ts.backend.log-without-context.ast',
|
|
817
|
+
]),
|
|
818
|
+
'skills.backend.guideline.backend.nestjs-config-configmodule-para-variables-de-entorno':
|
|
819
|
+
heuristicDetector('typescript.backend.direct-process-env-read', [
|
|
820
|
+
'heuristics.ts.backend.direct-process-env-read.ast',
|
|
821
|
+
]),
|
|
822
|
+
'skills.backend.guideline.backend.validation-de-config-joi-o-class-validator-para-env':
|
|
823
|
+
heuristicDetector('typescript.backend.config-module-without-validation', [
|
|
824
|
+
'heuristics.ts.backend.config-module-without-validation.ast',
|
|
825
|
+
]),
|
|
826
|
+
'skills.backend.guideline.backend.compression-gzip-para-responses-grandes':
|
|
827
|
+
heuristicDetector('typescript.backend.missing-compression-middleware', [
|
|
828
|
+
'heuristics.ts.backend.missing-compression-middleware.ast',
|
|
829
|
+
]),
|
|
784
830
|
'skills.backend.guideline.backend.soft-deletes-deletedat-en-lugar-de-delete-fi-sico':
|
|
785
831
|
heuristicDetector('typescript.backend.hard-delete-without-soft-delete', [
|
|
786
832
|
'heuristics.ts.backend.hard-delete-without-soft-delete.ast',
|
|
@@ -809,10 +855,26 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
809
855
|
heuristicDetector('typescript.backend.dto-property-without-validation', [
|
|
810
856
|
'heuristics.ts.backend.dto-property-without-validation.ast',
|
|
811
857
|
]),
|
|
858
|
+
'skills.backend.guideline.backend.swagger-nestjs-swagger-decoradores-apiproperty':
|
|
859
|
+
heuristicDetector('typescript.backend.dto-property-without-api-property', [
|
|
860
|
+
'heuristics.ts.backend.dto-property-without-api-property.ast',
|
|
861
|
+
]),
|
|
812
862
|
'skills.backend.guideline.backend.nested-validation-validatenested-type':
|
|
813
863
|
heuristicDetector('typescript.backend.dto-nested-property-without-nested-validation', [
|
|
814
864
|
'heuristics.ts.backend.dto-nested-property-without-nested-validation.ast',
|
|
815
865
|
]),
|
|
866
|
+
'skills.backend.guideline.backend.pipes-para-validacio-n-global-validationpipe-en-main-ts':
|
|
867
|
+
heuristicDetector('typescript.backend.missing-global-validation-pipe', [
|
|
868
|
+
'heuristics.ts.backend.missing-global-validation-pipe.ast',
|
|
869
|
+
]),
|
|
870
|
+
'skills.backend.guideline.backend.validationpipe-global-en-main-ts-con-whitelist-true':
|
|
871
|
+
heuristicDetector('typescript.backend.missing-global-validation-pipe', [
|
|
872
|
+
'heuristics.ts.backend.missing-global-validation-pipe.ast',
|
|
873
|
+
]),
|
|
874
|
+
'skills.backend.guideline.backend.helmet-security-headers':
|
|
875
|
+
heuristicDetector('typescript.backend.missing-helmet-security-headers', [
|
|
876
|
+
'heuristics.ts.backend.missing-helmet-security-headers.ast',
|
|
877
|
+
]),
|
|
816
878
|
'skills.backend.guideline.backend.guards-en-todas-las-rutas-protegidas-useguards-jwtauthguard':
|
|
817
879
|
heuristicDetector('typescript.backend.controller-route-without-guard', [
|
|
818
880
|
'heuristics.ts.backend.controller-route-without-guard.ast',
|
|
@@ -821,6 +883,18 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
821
883
|
heuristicDetector('typescript.backend.controller-route-without-guard', [
|
|
822
884
|
'heuristics.ts.backend.controller-route-without-guard.ast',
|
|
823
885
|
]),
|
|
886
|
+
'skills.backend.guideline.backend.role-based-access-control-roles-admin-user':
|
|
887
|
+
heuristicDetector('typescript.backend.controller-route-without-roles', [
|
|
888
|
+
'heuristics.ts.backend.controller-route-without-roles.ast',
|
|
889
|
+
]),
|
|
890
|
+
'skills.backend.guideline.backend.rate-limiting-nestjs-throttler-para-prevenir-brute-force':
|
|
891
|
+
heuristicDetector('typescript.backend.auth-route-without-throttle', [
|
|
892
|
+
'heuristics.ts.backend.auth-route-without-throttle.ast',
|
|
893
|
+
]),
|
|
894
|
+
'skills.backend.guideline.backend.rate-limiting-throttler-para-prevenir-abuse':
|
|
895
|
+
heuristicDetector('typescript.backend.auth-route-without-throttle', [
|
|
896
|
+
'heuristics.ts.backend.auth-route-without-throttle.ast',
|
|
897
|
+
]),
|
|
824
898
|
'skills.backend.guideline.backend.callback-hell-usar-async-await': heuristicDetector(
|
|
825
899
|
'typescript.callback-hell',
|
|
826
900
|
['heuristics.ts.callback-hell.ast']
|
|
@@ -898,6 +972,22 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
898
972
|
heuristicDetector('typescript.backend.controller-entity-response', [
|
|
899
973
|
'heuristics.ts.backend.controller-entity-response.ast',
|
|
900
974
|
]),
|
|
975
|
+
'skills.backend.guideline.backend.controllers-delgados-solo-routing-y-validacio-n-lo-gica-en-servicios':
|
|
976
|
+
heuristicDetector('typescript.backend.controller-business-logic', [
|
|
977
|
+
'heuristics.ts.backend.controller-business-logic.ast',
|
|
978
|
+
]),
|
|
979
|
+
'skills.backend.guideline.backend.lo-gica-en-controllers-mover-a-servicios-use-cases':
|
|
980
|
+
heuristicDetector('typescript.backend.controller-business-logic', [
|
|
981
|
+
'heuristics.ts.backend.controller-business-logic.ast',
|
|
982
|
+
]),
|
|
983
|
+
'skills.backend.guideline.backend.no-lo-gica-de-negocio-en-repositorios-solo-crud-y-queries':
|
|
984
|
+
heuristicDetector('typescript.backend.repository-business-logic', [
|
|
985
|
+
'heuristics.ts.backend.repository-business-logic.ast',
|
|
986
|
+
]),
|
|
987
|
+
'skills.backend.guideline.backend.repositories-para-datos-abstraer-acceso-a-bd-con-interfaces':
|
|
988
|
+
heuristicDetector('typescript.backend.repository-business-logic', [
|
|
989
|
+
'heuristics.ts.backend.repository-business-logic.ast',
|
|
990
|
+
]),
|
|
901
991
|
'skills.backend.guideline.backend.anemic-domain-models-entidades-solo-con-getters-setters':
|
|
902
992
|
heuristicDetector('typescript.backend.anemic-domain-model', [
|
|
903
993
|
'heuristics.ts.backend.anemic-domain-model.ast',
|
|
@@ -196,6 +196,29 @@ const isFindingOutsideChangedLines = (
|
|
|
196
196
|
return findingLines.every((line) => !changedLines.has(line));
|
|
197
197
|
};
|
|
198
198
|
|
|
199
|
+
const BROAD_BROWNFIELD_FINDING_LINES_THRESHOLD = 20;
|
|
200
|
+
|
|
201
|
+
const isBroadFileLevelFinding = (finding: Finding): boolean => {
|
|
202
|
+
const findingLines = normalizeFindingLines(finding.lines);
|
|
203
|
+
if (findingLines.length <= BROAD_BROWNFIELD_FINDING_LINES_THRESHOLD) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
const hasPreciseNode =
|
|
207
|
+
typeof finding.primary_node !== 'undefined' || (finding.related_nodes?.length ?? 0) > 0;
|
|
208
|
+
return !hasPreciseNode;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const isFindingTooBroadForStagedDiffBlock = (
|
|
212
|
+
finding: Finding,
|
|
213
|
+
changedLinesByPath: ReadonlyMap<string, ReadonlySet<number>>
|
|
214
|
+
): boolean => {
|
|
215
|
+
if (!finding.filePath || !isBroadFileLevelFinding(finding)) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
const changedLines = changedLinesByPath.get(toNormalizedPath(finding.filePath));
|
|
219
|
+
return typeof changedLines !== 'undefined' && changedLines.size > 0;
|
|
220
|
+
};
|
|
221
|
+
|
|
199
222
|
const normalizeScopedRuleEngineFindings = (params: {
|
|
200
223
|
findings: ReadonlyArray<Finding>;
|
|
201
224
|
scope: GateScope;
|
|
@@ -210,7 +233,18 @@ const normalizeScopedRuleEngineFindings = (params: {
|
|
|
210
233
|
}
|
|
211
234
|
|
|
212
235
|
return params.findings.map((finding) => {
|
|
213
|
-
if (!isAstRuleFinding(finding)
|
|
236
|
+
if (!isAstRuleFinding(finding)) {
|
|
237
|
+
return finding;
|
|
238
|
+
}
|
|
239
|
+
const outsideChangedLines = isFindingOutsideChangedLines(
|
|
240
|
+
finding,
|
|
241
|
+
params.changedLinesByPath
|
|
242
|
+
);
|
|
243
|
+
const tooBroadForDiffBlock = isFindingTooBroadForStagedDiffBlock(
|
|
244
|
+
finding,
|
|
245
|
+
params.changedLinesByPath
|
|
246
|
+
);
|
|
247
|
+
if (!outsideChangedLines && !tooBroadForDiffBlock) {
|
|
214
248
|
return finding;
|
|
215
249
|
}
|
|
216
250
|
return {
|
|
@@ -219,10 +253,14 @@ const normalizeScopedRuleEngineFindings = (params: {
|
|
|
219
253
|
severity: 'INFO',
|
|
220
254
|
message:
|
|
221
255
|
`${finding.message} ` +
|
|
222
|
-
|
|
256
|
+
(tooBroadForDiffBlock
|
|
257
|
+
? 'Finding is file-level/broad and cannot prove the violation was introduced by the staged diff; tracked as advisory for this atomic slice.'
|
|
258
|
+
: 'Baseline brownfield outside the staged diff; tracked as advisory for this atomic slice.'),
|
|
223
259
|
expected_fix:
|
|
224
260
|
finding.expected_fix ??
|
|
225
|
-
|
|
261
|
+
(tooBroadForDiffBlock
|
|
262
|
+
? 'Emit a precise AST/nodal finding with line-level evidence for the changed node, or plan a dedicated brownfield remediation slice for this file-level debt.'
|
|
263
|
+
: 'Plan a dedicated brownfield remediation slice for this pre-existing finding.'),
|
|
226
264
|
};
|
|
227
265
|
});
|
|
228
266
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.295",
|
|
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": {
|