pumuki 6.3.338 → 6.3.340

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.
@@ -1979,12 +1979,21 @@ final class Credentials {
1979
1979
  let label = "public title"
1980
1980
  // let apiKey = "sk_live_123456789"
1981
1981
  }
1982
+ `;
1983
+ const emptyFormDefaults = `
1984
+ @MainActor
1985
+ public final class BuyerAppViewModel {
1986
+ public var authEmail: String = ""
1987
+ public var authPassword: String = ""
1988
+ }
1982
1989
  `;
1983
1990
 
1984
1991
  assert.equal(hasSwiftHardcodedSensitiveStringUsage(source), true);
1985
1992
  assert.deepEqual(collectSwiftHardcodedSensitiveStringLines(source), [3, 4]);
1986
1993
  assert.equal(hasSwiftHardcodedSensitiveStringUsage(safe), false);
1987
1994
  assert.deepEqual(collectSwiftHardcodedSensitiveStringLines(safe), []);
1995
+ assert.equal(hasSwiftHardcodedSensitiveStringUsage(emptyFormDefaults), false);
1996
+ assert.deepEqual(collectSwiftHardcodedSensitiveStringLines(emptyFormDefaults), []);
1988
1997
  });
1989
1998
 
1990
1999
  test('hasSwiftUnlocalizedDateFormatterUsage detecta dateFormat fijo sin locale explicito', () => {
@@ -1718,18 +1718,26 @@ export const collectSwiftSensitiveLoggingLines = (source: string): readonly numb
1718
1718
  return sortedUniqueLines(lines);
1719
1719
  };
1720
1720
 
1721
- export const hasSwiftHardcodedSensitiveStringUsage = (source: string): boolean => {
1722
- return collectSwiftRegexLines(
1723
- source,
1724
- /\b(?:(?:private|fileprivate|internal|public|open|static|class|final|lazy)\s+)*(?:let|var)\s+(?=[A-Za-z_])[A-Za-z0-9_]*(?:token|secret|password|apikey|clientsecret|privatekey|sessionid)[A-Za-z0-9_]*\s*(?::\s*String\s*)?=\s*""/i
1725
- ).length > 0;
1726
- };
1721
+ const swiftHardcodedSensitiveStringPattern =
1722
+ /\b(?:(?:private|fileprivate|internal|public|open|static|class|final|lazy)\s+)*(?:let|var)\s+(?=[A-Za-z_])[A-Za-z0-9_]*(?:token|secret|password|apikey|clientsecret|privatekey|sessionid)[A-Za-z0-9_]*\s*(?::\s*String\s*)?=\s*"((?:\\.|[^"\\])*)"/i;
1727
1723
 
1728
1724
  export const collectSwiftHardcodedSensitiveStringLines = (source: string): readonly number[] => {
1729
- return collectSwiftRegexLines(
1730
- source,
1731
- /\b(?:(?:private|fileprivate|internal|public|open|static|class|final|lazy)\s+)*(?:let|var)\s+(?=[A-Za-z_])[A-Za-z0-9_]*(?:token|secret|password|apikey|clientsecret|privatekey|sessionid)[A-Za-z0-9_]*\s*(?::\s*String\s*)?=\s*""/i
1732
- );
1725
+ const matches: number[] = [];
1726
+
1727
+ source.split(/\r?\n/).forEach((rawLine, index) => {
1728
+ const line = rawLine.replace(/\/\/.*$/, '');
1729
+ const match = swiftHardcodedSensitiveStringPattern.exec(line);
1730
+ const literalValue = match?.[1] ?? '';
1731
+ if (literalValue.length > 0) {
1732
+ matches.push(index + 1);
1733
+ }
1734
+ });
1735
+
1736
+ return matches;
1737
+ };
1738
+
1739
+ export const hasSwiftHardcodedSensitiveStringUsage = (source: string): boolean => {
1740
+ return collectSwiftHardcodedSensitiveStringLines(source).length > 0;
1733
1741
  };
1734
1742
 
1735
1743
  export const hasSwiftUnlocalizedDateFormatterUsage = (source: string): boolean => {
@@ -76,25 +76,56 @@ const normalizeRuleCode = (ruleId: string): string =>
76
76
  .replace(/[.-]/gu, '_')
77
77
  .toUpperCase();
78
78
 
79
+ const extractMessageField = (message: string, field: string): string | undefined => {
80
+ const escapedField = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
81
+ const match = message.match(new RegExp(`\\b${escapedField}=([^\\n]+?)(?=\\s(?:severity|code|rule|file|lines?|message|remediation|snippet|node|primary_node|missing)=|\\s\\|\\|\\s\\d+\\)|$)`, 'i'));
82
+ const value = match?.[1]?.trim();
83
+ return value && value.length > 0 ? value : undefined;
84
+ };
85
+
86
+ const extractFirstNestedSkillSegment = (message: string): string =>
87
+ message
88
+ .replace(/^.*?\bBlocking causes:\s*1\)\s*/isu, '')
89
+ .replace(/\s+\|\|\s+\d+\)\s+[\s\S]*$/u, '')
90
+ .trim();
91
+
92
+ const normalizeNestedSkillMessage = (params: {
93
+ ruleId: string;
94
+ segment: string;
95
+ }): string => {
96
+ if (/\bmessage=/i.test(params.segment)) {
97
+ return params.segment;
98
+ }
99
+ const withoutRule = params.segment.replace(params.ruleId, '').trim();
100
+ return `message=${withoutRule || 'Skill violada.'}`;
101
+ };
102
+
79
103
  const extractNestedSkillCauseFromWrapper = (cause: NotificationBlockingCause): NotificationBlockingCause => {
80
104
  if (cause.ruleId?.startsWith('skills.') || cause.code.startsWith('SKILLS_')) {
81
105
  return cause;
82
106
  }
83
- const nested = cause.message.match(/\bBlocking causes:\s*1\)\s*(skills\.[a-z0-9_.-]+)\s+(.+?)$/iu);
107
+ const nested = cause.message.match(/\bBlocking causes:\s*1\)\s*(skills\.[a-z0-9_.-]+)\s+(.+?)$/isu);
84
108
  if (!nested?.[1]) {
85
109
  return cause;
86
110
  }
87
111
  const ruleId = nested[1];
88
- const nestedMessage = nested[2]?.trim() || 'Skill violada.';
112
+ const nestedMessage = extractFirstNestedSkillSegment(cause.message) || nested[2]?.trim() || 'Skill violada.';
113
+ const normalizedNestedMessage = normalizeNestedSkillMessage({
114
+ ruleId,
115
+ segment: nestedMessage,
116
+ });
117
+ const nestedFile = extractMessageField(normalizedNestedMessage, 'file');
118
+ const nestedRemediation = extractMessageField(normalizedNestedMessage, 'remediation');
89
119
  return {
90
120
  ...cause,
91
121
  code: normalizeRuleCode(ruleId),
92
122
  ruleId,
93
- message: `rule=${ruleId} message=${nestedMessage}`,
123
+ file: nestedFile ?? cause.file,
124
+ message: `rule=${ruleId} ${normalizedNestedMessage}`,
94
125
  remediation:
95
- cause.remediation && !/corrige la violaci[oó]n indicada/i.test(cause.remediation)
126
+ cause.remediation && !/corrige la violaci[oó]n indicada|corrige la causa bloqueante/i.test(cause.remediation)
96
127
  ? cause.remediation
97
- : 'Corrige la violación de la skill indicada en el fichero afectado y vuelve a intentar el commit.',
128
+ : nestedRemediation ?? 'Corrige la violación de la skill indicada en el fichero afectado y vuelve a intentar el commit.',
98
129
  };
99
130
  };
100
131
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.338",
3
+ "version": "6.3.340",
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": {
@@ -168,7 +168,7 @@ const formatVisibleRule = (cause: BlockedCause): string => {
168
168
 
169
169
  const extractMessageField = (message: string, field: string): string | null => {
170
170
  const escapedField = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
171
- const match = message.match(new RegExp(`\\b${escapedField}=([^\\n]+?)(?=\\s(?:severity|code|rule|file|lines?|message|remediation|snippet|node|primary_node|missing)=|$)`, 'i'));
171
+ const match = message.match(new RegExp(`\\b${escapedField}=([^\\n]+?)(?=\\s(?:severity|code|rule|file|lines?|message|remediation|snippet|node|primary_node|missing)=|\\s\\|\\|\\s\\d+\\)|$)`, 'i'));
172
172
  const value = match?.[1]?.trim();
173
173
  return value && value.length > 0 ? normalizeNotificationText(value) : null;
174
174
  };
@@ -208,11 +208,18 @@ const normalizeRuleCode = (ruleId: string): string =>
208
208
  const isGenericCauseFix = (value?: string): boolean =>
209
209
  !value ||
210
210
  /corrige la violaci[oó]n indicada/i.test(value) ||
211
- /corrige las violaciones listadas/i.test(value);
211
+ /corrige las violaciones listadas/i.test(value) ||
212
+ /corrige la causa bloqueante/i.test(value);
212
213
 
213
214
  const extractNestedSkillRuleId = (message: string): string | null =>
214
215
  message.match(/\b(skills\.[a-z0-9_.-]+)\b/iu)?.[1] ?? null;
215
216
 
217
+ const extractFirstNestedSkillSegment = (message: string): string =>
218
+ message
219
+ .replace(/^.*?\bBlocking causes:\s*1\)\s*/isu, '')
220
+ .replace(/\s+\|\|\s+\d+\)\s+[\s\S]*$/u, '')
221
+ .trim();
222
+
216
223
  const normalizeDisplayCause = (cause: BlockedCause): BlockedCause => {
217
224
  if (isSkillCause(cause) || isSkillsContractCause(cause)) {
218
225
  return cause;
@@ -221,15 +228,17 @@ const normalizeDisplayCause = (cause: BlockedCause): BlockedCause => {
221
228
  if (!nestedSkillRuleId) {
222
229
  return cause;
223
230
  }
224
- const nestedFile = extractMessageField(cause.message, 'file');
225
- const nestedRemediation = extractMessageField(cause.message, 'remediation');
231
+ const nestedSegment = extractFirstNestedSkillSegment(cause.message);
232
+ const nestedFile = extractMessageField(nestedSegment, 'file');
233
+ const nestedRemediation = extractMessageField(nestedSegment, 'remediation');
226
234
  return {
227
235
  ...cause,
228
236
  code: normalizeRuleCode(nestedSkillRuleId),
229
237
  ruleId: nestedSkillRuleId,
230
238
  file: nestedFile ?? cause.file,
239
+ message: nestedSegment,
231
240
  remediation: isGenericCauseFix(cause.remediation)
232
- ? nestedRemediation ?? cause.remediation
241
+ ? nestedRemediation ?? 'Corrige la violación de la skill indicada en el fichero afectado y vuelve a intentar el commit.'
233
242
  : cause.remediation,
234
243
  };
235
244
  };