pumuki 6.3.362 → 6.3.364

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.
@@ -180,9 +180,11 @@ import {
180
180
  hasSwiftSensitiveLoggingUsage,
181
181
  hasSwiftSelfPrintChangesUsage,
182
182
  collectSwiftInsecureTransportLines,
183
+ collectSwiftUrlSessionTrustBypassLines,
183
184
  collectSwiftSensitiveUserDefaultsStorageLines,
184
185
  hasSwiftSensitiveUserDefaultsStorageUsage,
185
186
  hasSwiftInsecureTransportUsage,
187
+ hasSwiftUrlSessionTrustBypassUsage,
186
188
  hasSwiftJSONSerializationUsage,
187
189
  collectSwiftJSONSerializationLines,
188
190
  hasSwiftExplicitColorStaticMemberUsage,
@@ -229,6 +231,41 @@ let value = loadUser()!
229
231
  assert.deepEqual(collectSwiftForceUnwrapLines(source), [2, 3]);
230
232
  });
231
233
 
234
+ test('hasSwiftUrlSessionTrustBypassUsage detecta delegate que acepta cualquier certificado', () => {
235
+ const source = `
236
+ final class InsecureDelegate: NSObject, URLSessionDelegate {
237
+ func urlSession(
238
+ _ session: URLSession,
239
+ didReceive challenge: URLAuthenticationChallenge,
240
+ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
241
+ ) {
242
+ completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
243
+ }
244
+ }
245
+ `;
246
+
247
+ assert.equal(hasSwiftUrlSessionTrustBypassUsage(source), true);
248
+ assert.deepEqual(collectSwiftUrlSessionTrustBypassLines(source), [8]);
249
+ });
250
+
251
+ test('hasSwiftUrlSessionTrustBypassUsage preserva cancelacion o manejo por defecto del challenge TLS', () => {
252
+ const source = `
253
+ final class SecureDelegate: NSObject, URLSessionDelegate {
254
+ func urlSession(
255
+ _ session: URLSession,
256
+ didReceive challenge: URLAuthenticationChallenge,
257
+ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
258
+ ) {
259
+ completionHandler(.performDefaultHandling, nil)
260
+ completionHandler(.cancelAuthenticationChallenge, nil)
261
+ }
262
+ }
263
+ `;
264
+
265
+ assert.equal(hasSwiftUrlSessionTrustBypassUsage(source), false);
266
+ assert.deepEqual(collectSwiftUrlSessionTrustBypassLines(source), []);
267
+ });
268
+
232
269
  test('hasSwiftForceUnwrap excluye type annotations, force cast y operadores', () => {
233
270
  const source = `
234
271
  let name: String!
@@ -1940,6 +1940,27 @@ export const collectSwiftInsecureTransportLines = (source: string): readonly num
1940
1940
  return sortedUniqueLines(result);
1941
1941
  };
1942
1942
 
1943
+ export const collectSwiftUrlSessionTrustBypassLines = (source: string): readonly number[] => {
1944
+ const result: number[] = [];
1945
+
1946
+ source.split(/\r?\n/).forEach((line, index) => {
1947
+ const sanitized = stripSwiftLineForSemanticScan(line);
1948
+ if (
1949
+ /completionHandler\s*\(\s*\.useCredential\s*,\s*URLCredential\s*\(\s*trust\s*:/.test(
1950
+ sanitized
1951
+ )
1952
+ ) {
1953
+ result.push(index + 1);
1954
+ }
1955
+ });
1956
+
1957
+ return sortedUniqueLines(result);
1958
+ };
1959
+
1960
+ export const hasSwiftUrlSessionTrustBypassUsage = (source: string): boolean => {
1961
+ return collectSwiftUrlSessionTrustBypassLines(source).length > 0;
1962
+ };
1963
+
1943
1964
  const swiftUiLiteralTextPatterns = [
1944
1965
  /\b(?:Text|Button|Label|TextField|SecureField)\s*\(\s*"((?:\\.|[^"\\])*)"/,
1945
1966
  /\.navigationTitle\s*\(\s*"((?:\\.|[^"\\])*)"/,
@@ -812,6 +812,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
812
812
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftJSONSerializationUsage, locateLines: TextIOS.collectSwiftJSONSerializationLines, primaryNode: (lines) => ({ kind: 'call', name: 'JSONSerialization call', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: Codable decoder or encoder', lines }], why: 'JSONSerialization bypasses typed decoding and makes payload contracts harder to validate than Codable models.', impact: 'Runtime casts and dictionary traversal can hide API drift until production and make the gate report vague file-level serialization debt.', expected_fix: 'Replace JSONSerialization calls with Codable DTOs using JSONDecoder or JSONEncoder at the repository networking boundary.', ruleId: 'heuristics.ios.json.jsonserialization.ast', code: 'HEURISTICS_IOS_JSON_JSONSERIALIZATION_AST', message: 'AST heuristic detected JSONSerialization usage in iOS production code; Codable remains the preferred baseline for new code.' },
813
813
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftSensitiveUserDefaultsStorageUsage, locateLines: TextIOS.collectSwiftSensitiveUserDefaultsStorageLines, primaryNode: (lines) => ({ kind: 'call', name: 'sensitive UserDefaults/AppStorage storage', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: native Keychain or secure secret store', lines }], why: 'Tokens, passwords, credentials and session identifiers must not be stored in UserDefaults or AppStorage because those stores are not the approved secret boundary.', impact: 'Secrets persisted in UserDefaults/AppStorage can leak through backups, diagnostics or simple local inspection, and the gate needs the exact storage node to avoid whole-file remediation.', expected_fix: 'Move tokens, passwords, credentials and session identifiers to native Keychain or the repository-approved secure storage adapter. Keep UserDefaults/AppStorage only for non-sensitive preferences.', ruleId: 'heuristics.ios.security.userdefaults-sensitive-data.ast', code: 'HEURISTICS_IOS_SECURITY_USERDEFAULTS_SENSITIVE_DATA_AST', message: 'AST heuristic detected sensitive data stored in UserDefaults/AppStorage; native Keychain remains the preferred baseline for secrets.' },
814
814
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftInsecureTransportUsage, locateLines: TextIOS.collectSwiftInsecureTransportLines, primaryNode: (lines) => ({ kind: 'call', name: 'insecure HTTP URL literal', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: HTTPS URLSession endpoint with ATS enabled', lines }], why: 'Production iOS networking must use HTTPS and keep App Transport Security enabled by default.', impact: 'HTTP endpoints can expose credentials, session data or payloads in transit and create release-blocking transport exceptions.', expected_fix: 'Replace http:// endpoints with https:// endpoints and keep ATS enabled. If a temporary exception is unavoidable, isolate it to a documented debug-only configuration, not production code.', ruleId: 'heuristics.ios.security.insecure-transport.ast', code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST', message: 'AST heuristic detected insecure HTTP transport in iOS production code.' },
815
+ { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUrlSessionTrustBypassUsage, locateLines: TextIOS.collectSwiftUrlSessionTrustBypassLines, primaryNode: (lines) => ({ kind: 'call', name: 'URLSession trust challenge accepted without validation', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: validate server trust or use default URLSession trust handling', lines }], why: 'Production iOS networking must not accept arbitrary TLS server trust in URLSessionDelegate callbacks.', impact: 'Accepting URLCredential(trust:) directly for the server trust challenge disables effective certificate validation and can expose sessions to man-in-the-middle attacks.', expected_fix: 'Remove unconditional .useCredential handling. Use default trust handling, cancel invalid challenges, or implement explicit certificate/public-key pinning with a documented trust evaluator.', ruleId: 'heuristics.ios.security.urlsession-trust-bypass.ast', code: 'HEURISTICS_IOS_SECURITY_URLSESSION_TRUST_BYPASS_AST', message: 'AST heuristic detected URLSession trust challenge bypass in iOS production code.' },
815
816
  { platform: 'ios', pathCheck: isIOSInfoPlistPath, excludePaths: [], detect: TextIOS.hasSwiftInsecureTransportUsage, locateLines: TextIOS.collectSwiftInsecureTransportLines, primaryNode: (lines) => ({ kind: 'property', name: 'ATS NSAllowsArbitraryLoads enabled', lines }), relatedNodes: (lines) => [{ kind: 'property', name: 'replacement: ATS enabled with explicit HTTPS-only exceptions', lines }], why: 'NSAllowsArbitraryLoads disables the default iOS App Transport Security protection and should not be enabled for production builds.', impact: 'Permissive ATS configuration allows insecure transport globally, making networking violations harder to audit per endpoint.', expected_fix: 'Remove NSAllowsArbitraryLoads=true. Keep ATS enabled by default and add the narrowest documented domain exception only when the production requirement is approved.', ruleId: 'heuristics.ios.security.insecure-transport.ast', code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST', message: 'AST heuristic detected permissive App Transport Security configuration.' },
816
817
  { platform: 'ios', pathCheck: isIOSLocalizableStringsPath, excludePaths: [], detect: detectsTrackedFilePresence, ruleId: 'heuristics.ios.localization.localizable-strings.ast', code: 'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST', message: 'AST heuristic detected Localizable.strings usage; String Catalogs (.xcstrings) remain the preferred baseline for new localization work.' },
817
818
  { platform: 'ios', pathCheck: isIOSInterfaceBuilderPath, excludePaths: [], detect: detectsTrackedFilePresence, ruleId: 'heuristics.ios.interface-builder.storyboard-xib.ast', code: 'HEURISTICS_IOS_INTERFACE_BUILDER_STORYBOARD_XIB_AST', message: 'AST heuristic detected Storyboard/XIB usage; programmatic SwiftUI/UIKit UI remains the preferred baseline for versionable iOS code.' },
@@ -3,7 +3,7 @@ import test from 'node:test';
3
3
  import { iosRules } from './ios';
4
4
 
5
5
  test('iosRules define reglas heurísticas locked para plataforma ios', () => {
6
- assert.equal(iosRules.length, 136);
6
+ assert.equal(iosRules.length, 137);
7
7
 
8
8
  const ids = iosRules.map((rule) => rule.id);
9
9
  assert.deepEqual(ids, [
@@ -69,6 +69,7 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
69
69
  'heuristics.ios.uikit.cell-without-reuse.ast',
70
70
  'heuristics.ios.security.userdefaults-sensitive-data.ast',
71
71
  'heuristics.ios.security.insecure-transport.ast',
72
+ 'heuristics.ios.security.urlsession-trust-bypass.ast',
72
73
  'heuristics.ios.localization.localizable-strings.ast',
73
74
  'heuristics.ios.interface-builder.storyboard-xib.ast',
74
75
  'heuristics.ios.localization.hardcoded-ui-string.ast',
@@ -1145,6 +1145,24 @@ export const iosRules: RuleSet = [
1145
1145
  code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST',
1146
1146
  },
1147
1147
  },
1148
+ {
1149
+ id: 'heuristics.ios.security.urlsession-trust-bypass.ast',
1150
+ description: 'Detects URLSessionDelegate trust challenge handlers that accept server trust without validation.',
1151
+ severity: 'WARN',
1152
+ platform: 'ios',
1153
+ locked: true,
1154
+ when: {
1155
+ kind: 'Heuristic',
1156
+ where: {
1157
+ ruleId: 'heuristics.ios.security.urlsession-trust-bypass.ast',
1158
+ },
1159
+ },
1160
+ then: {
1161
+ kind: 'Finding',
1162
+ message: 'AST heuristic detected URLSession trust challenge bypass in iOS production code.',
1163
+ code: 'HEURISTICS_IOS_SECURITY_URLSESSION_TRUST_BYPASS_AST',
1164
+ },
1165
+ },
1148
1166
  {
1149
1167
  id: 'heuristics.ios.localization.localizable-strings.ast',
1150
1168
  description: 'Detects legacy Localizable.strings files where String Catalogs are the preferred iOS baseline.',
@@ -236,6 +236,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
236
236
  'ios.logging.sensitive-data',
237
237
  ['heuristics.ios.logging.sensitive-data.ast']
238
238
  ),
239
+ 'skills.ios.guideline.ios.request-response-interceptors-logging-auth-tokens': heuristicDetector(
240
+ 'ios.logging.sensitive-data',
241
+ ['heuristics.ios.logging.sensitive-data.ast']
242
+ ),
239
243
  'skills.ios.guideline.ios.obfuscation-strings-sensibles-en-co-digo': heuristicDetector(
240
244
  'ios.security.hardcoded-sensitive-string',
241
245
  ['heuristics.ios.security.hardcoded-sensitive-string.ast']
@@ -304,6 +308,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
304
308
  'ios.security.insecure-transport',
305
309
  ['heuristics.ios.security.insecure-transport.ast']
306
310
  ),
311
+ 'skills.ios.guideline.ios.ssl-pinning-para-apps-con-alta-seguridad': heuristicDetector(
312
+ 'ios.security.urlsession-trust-bypass',
313
+ ['heuristics.ios.security.urlsession-trust-bypass.ast']
314
+ ),
315
+ 'skills.ios.guideline.ios.ssl-pinning-prevenir-man-in-the-middle': heuristicDetector(
316
+ 'ios.security.urlsession-trust-bypass',
317
+ ['heuristics.ios.security.urlsession-trust-bypass.ast']
318
+ ),
307
319
  'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs':
308
320
  heuristicDetector('ios.localization.localizable-strings', [
309
321
  'heuristics.ios.localization.localizable-strings.ast',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.362",
3
+ "version": "6.3.364",
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": {
package/skills.lock.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "1.0",
3
3
  "compilerVersion": "1.0.0",
4
- "generatedAt": "2026-05-24T21:20:37.941Z",
4
+ "generatedAt": "2026-05-25T04:24:35.613Z",
5
5
  "bundles": [
6
6
  {
7
7
  "name": "android-guidelines",