pumuki 6.3.231 → 6.3.232

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.
@@ -75,3 +75,33 @@ test('evaluateGate devuelve BLOCK cuando existe al menos un finding bloqueante',
75
75
  assert.equal(result.warnings.length, 1);
76
76
  assert.equal(result.warnings[0]?.ruleId, 'rule.warn');
77
77
  });
78
+
79
+ test('evaluateGate bloquea cualquier severidad cuando la policy zero-violations usa INFO', () => {
80
+ const findings: Finding[] = [
81
+ {
82
+ ruleId: 'rule.info',
83
+ severity: 'INFO',
84
+ code: 'RULE_INFO',
85
+ message: 'Info finding',
86
+ },
87
+ {
88
+ ruleId: 'rule.warn',
89
+ severity: 'WARN',
90
+ code: 'RULE_WARN',
91
+ message: 'Warn finding',
92
+ },
93
+ ];
94
+
95
+ const result = evaluateGate(findings, {
96
+ stage: 'PRE_PUSH',
97
+ blockOnOrAbove: 'INFO',
98
+ warnOnOrAbove: 'INFO',
99
+ });
100
+
101
+ assert.equal(result.outcome, 'BLOCK');
102
+ assert.deepEqual(
103
+ result.blocking.map((finding) => finding.ruleId),
104
+ ['rule.info', 'rule.warn']
105
+ );
106
+ assert.deepEqual(result.warnings, []);
107
+ });
@@ -32,15 +32,46 @@ test('evaluateRules genera finding cuando la condicion coincide y usa code expli
32
32
  const findings = evaluateRules(rules, facts);
33
33
 
34
34
  assert.equal(findings.length, 1);
35
- assert.deepEqual(findings[0], {
36
- ruleId: 'rule.explicit.code',
37
- severity: 'WARN',
38
- code: 'BACKEND_FILE_MODIFIED',
39
- message: 'Backend file modified.',
40
- filePath: 'apps/backend/src/main.ts',
41
- matchedBy: 'FileChange',
42
- source: 'git',
43
- });
35
+ assert.equal(findings[0]?.ruleId, 'rule.explicit.code');
36
+ assert.equal(findings[0]?.severity, 'WARN');
37
+ assert.equal(findings[0]?.code, 'BACKEND_FILE_MODIFIED');
38
+ assert.equal(findings[0]?.message, 'Backend file modified.');
39
+ assert.equal(findings[0]?.filePath, 'apps/backend/src/main.ts');
40
+ assert.equal(findings[0]?.matchedBy, 'FileChange');
41
+ assert.equal(findings[0]?.source, 'git');
42
+ assert.equal(findings[0]?.blocking, true);
43
+ });
44
+
45
+ test('evaluateRules marca cualquier severity como bloqueante bajo contrato zero-violations', () => {
46
+ const rules: RuleSet = [
47
+ {
48
+ id: 'rule.info.blocking',
49
+ description: 'Info still blocks in enterprise zero-violations mode.',
50
+ severity: 'INFO',
51
+ when: {
52
+ kind: 'FileChange',
53
+ where: { pathPrefix: 'apps/frontend/', changeType: 'modified' },
54
+ },
55
+ then: {
56
+ kind: 'Finding',
57
+ message: 'Any finding blocks.',
58
+ },
59
+ },
60
+ ];
61
+ const facts = [
62
+ {
63
+ kind: 'FileChange',
64
+ path: 'apps/frontend/src/App.tsx',
65
+ changeType: 'modified',
66
+ source: 'git',
67
+ },
68
+ ] as const;
69
+
70
+ const findings = evaluateRules(rules, facts);
71
+
72
+ assert.equal(findings.length, 1);
73
+ assert.equal(findings[0]?.severity, 'INFO');
74
+ assert.equal(findings[0]?.blocking, true);
44
75
  });
45
76
 
46
77
  test('evaluateRules usa id de la regla como code cuando no se define en consecuencia', () => {
@@ -23,8 +23,7 @@ type FindingTarget = {
23
23
  expected_fix?: string;
24
24
  };
25
25
 
26
- const isBlockingSeverity = (severity: RuleDefinition['severity']): boolean =>
27
- severity === 'CRITICAL' || severity === 'ERROR';
26
+ const isBlockingSeverity = (_severity: RuleDefinition['severity']): boolean => true;
28
27
 
29
28
  export type EvaluateRulesCoverageResult = {
30
29
  findings: ReadonlyArray<Finding>;
@@ -85,26 +85,37 @@ const toGatePolicyRecordFromEnterpriseThresholds = (
85
85
  };
86
86
  };
87
87
 
88
+ const ZERO_VIOLATION_BLOCK_ON_OR_ABOVE: GatePolicy['blockOnOrAbove'] = 'INFO';
89
+ const ZERO_VIOLATION_WARN_ON_OR_ABOVE: GatePolicy['warnOnOrAbove'] = 'INFO';
90
+
91
+ const enforceZeroViolationPolicy = (policy: GatePolicy): GatePolicy => {
92
+ return {
93
+ ...policy,
94
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
95
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
96
+ };
97
+ };
98
+
88
99
  const defaultPolicyByStage: Record<SkillsStage, GatePolicy> = {
89
100
  PRE_WRITE: {
90
101
  stage: 'PRE_WRITE',
91
- blockOnOrAbove: 'ERROR',
92
- warnOnOrAbove: 'WARN',
102
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
103
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
93
104
  },
94
105
  PRE_COMMIT: {
95
106
  stage: 'PRE_COMMIT',
96
- blockOnOrAbove: 'ERROR',
97
- warnOnOrAbove: 'WARN',
107
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
108
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
98
109
  },
99
110
  PRE_PUSH: {
100
111
  stage: 'PRE_PUSH',
101
- blockOnOrAbove: 'ERROR',
102
- warnOnOrAbove: 'WARN',
112
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
113
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
103
114
  },
104
115
  CI: {
105
116
  stage: 'CI',
106
- blockOnOrAbove: 'ERROR',
107
- warnOnOrAbove: 'WARN',
117
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
118
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
108
119
  },
109
120
  };
110
121
 
@@ -374,7 +385,7 @@ export const resolveExplicitPolicyProfileForStage = (
374
385
  const profilePolicy = profileName
375
386
  ? hardModePolicyProfileByStage[profileName][stage]
376
387
  : null;
377
- const hardModePolicy = profilePolicy ?? hardModePolicyByStage[stage];
388
+ const hardModePolicy = enforceZeroViolationPolicy(profilePolicy ?? hardModePolicyByStage[stage]);
378
389
  return {
379
390
  policy: hardModePolicy,
380
391
  source: 'hard-mode',
@@ -394,8 +405,8 @@ export const resolveExplicitPolicyProfileForStage = (
394
405
  return {
395
406
  policy: {
396
407
  stage: defaults.stage,
397
- blockOnOrAbove: stageOverride.blockOnOrAbove,
398
- warnOnOrAbove: stageOverride.warnOnOrAbove,
408
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
409
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
399
410
  },
400
411
  source: 'skills.policy',
401
412
  layer: 'policy-pack',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.231",
3
+ "version": "6.3.232",
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": {
@@ -8,20 +8,20 @@ export const buildAuditSummaryPayload = (
8
8
  ): SystemNotificationPayload => {
9
9
  if (event.criticalViolations > 0) {
10
10
  return {
11
- title: 'AST Audit Complete',
11
+ title: 'AST Audit Blocked',
12
12
  message: `🔴 ${event.criticalViolations} CRITICAL, ${event.highViolations} HIGH violations`,
13
13
  };
14
14
  }
15
15
  if (event.highViolations > 0) {
16
16
  return {
17
- title: 'AST Audit Complete',
17
+ title: 'AST Audit Blocked',
18
18
  message: `🟡 ${event.highViolations} HIGH violations found`,
19
19
  };
20
20
  }
21
21
  if (event.totalViolations > 0) {
22
22
  return {
23
- title: 'AST Audit Complete',
24
- message: `🔵 ${event.totalViolations} violations (no blockers)`,
23
+ title: 'AST Audit Blocked',
24
+ message: `🔴 ${event.totalViolations} violations block the gate`,
25
25
  };
26
26
  }
27
27
  return {