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
|
-
|
|
1722
|
-
|
|
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
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
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+(.+?)$/
|
|
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
|
-
|
|
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.
|
|
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)
|
|
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
|
|
225
|
-
const
|
|
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 ??
|
|
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
|
};
|