pumuki 6.3.196 → 6.3.197

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.
@@ -45,6 +45,7 @@ import {
45
45
  hasSwiftScrollViewShowsIndicatorsUsage,
46
46
  hasSwiftSensitiveLoggingUsage,
47
47
  hasSwiftSensitiveUserDefaultsStorageUsage,
48
+ hasSwiftInsecureTransportUsage,
48
49
  hasSwiftJSONSerializationUsage,
49
50
  hasSwiftStringFormatUsage,
50
51
  hasSwiftTabItemUsage,
@@ -240,6 +241,33 @@ let text = "UserDefaults.standard.set(accessToken, forKey: \\"accessToken\\")"
240
241
  assert.equal(hasSwiftSensitiveUserDefaultsStorageUsage(ignored), false);
241
242
  });
242
243
 
244
+ test('detector iOS de seguridad detecta transporte inseguro HTTP y ATS permisivo', () => {
245
+ const source = `
246
+ final class CatalogClient {
247
+ func load() {
248
+ _ = URL(string: "http://example.com/catalog.json")
249
+ }
250
+ }
251
+ `;
252
+ const plist = `
253
+ <dict>
254
+ <key>NSAppTransportSecurity</key>
255
+ <dict>
256
+ <key>NSAllowsArbitraryLoads</key>
257
+ <true/>
258
+ </dict>
259
+ </dict>
260
+ `;
261
+ const ignored = `
262
+ // _ = URL(string: "http://example.com/catalog.json")
263
+ let text = "https://example.com/catalog.json"
264
+ `;
265
+
266
+ assert.equal(hasSwiftInsecureTransportUsage(source), true);
267
+ assert.equal(hasSwiftInsecureTransportUsage(plist), true);
268
+ assert.equal(hasSwiftInsecureTransportUsage(ignored), false);
269
+ });
270
+
243
271
  test('hasSwiftUncheckedSendableUsage detecta @unchecked Sendable', () => {
244
272
  const source = `
245
273
  final class LegacyBox: @unchecked Sendable {}
@@ -492,6 +492,25 @@ export const hasSwiftSensitiveUserDefaultsStorageUsage = (source: string): boole
492
492
  });
493
493
  };
494
494
 
495
+ export const hasSwiftInsecureTransportUsage = (source: string): boolean => {
496
+ const withoutBlockComments = source.replace(/\/\*[\s\S]*?\*\//g, '\n');
497
+ const hasHttpUrlLiteral = withoutBlockComments.split(/\r?\n/).some((line) => {
498
+ if (/^\s*\/\//.test(line)) {
499
+ return false;
500
+ }
501
+ return /["']http:\/\/[^"']*["']/.test(line);
502
+ });
503
+
504
+ if (hasHttpUrlLiteral) {
505
+ return true;
506
+ }
507
+
508
+ return (
509
+ /<key>\s*NSAllowsArbitraryLoads\s*<\/key>\s*<true\s*\/>/i.test(source) ||
510
+ /\bNSAllowsArbitraryLoads\b\s*=\s*(?:true|YES|1)\b/i.test(source)
511
+ );
512
+ };
513
+
495
514
  export const hasSwiftUncheckedSendableUsage = (source: string): boolean => {
496
515
  return scanCodeLikeSource(source, ({ source: swiftSource, index, current }) => {
497
516
  if (current !== '@' || !swiftSource.startsWith('@unchecked', index)) {
@@ -92,6 +92,11 @@ const isIOSCartfilePath = (path: string): boolean => {
92
92
  );
93
93
  };
94
94
 
95
+ const isIOSInfoPlistPath = (path: string): boolean => {
96
+ const normalized = path.replace(/\\/g, '/');
97
+ return normalized.startsWith('apps/ios/') && normalized.endsWith('/Info.plist');
98
+ };
99
+
95
100
  const isIOSApplicationOrPresentationPath = (path: string): boolean => {
96
101
  return (
97
102
  isIOSSwiftPath(path) &&
@@ -641,6 +646,8 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
641
646
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAlamofireUsage, ruleId: 'heuristics.ios.networking.alamofire.ast', code: 'HEURISTICS_IOS_NETWORKING_ALAMOFIRE_AST', message: 'AST heuristic detected Alamofire usage in iOS production code; URLSession remains the preferred baseline for new code.' },
642
647
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftJSONSerializationUsage, 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.' },
643
648
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftSensitiveUserDefaultsStorageUsage, 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.' },
649
+ { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftInsecureTransportUsage, 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; HTTPS and ATS remain the preferred baseline.' },
650
+ { platform: 'ios', pathCheck: isIOSInfoPlistPath, excludePaths: [], detect: TextIOS.hasSwiftInsecureTransportUsage, ruleId: 'heuristics.ios.security.insecure-transport.ast', code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST', message: 'AST heuristic detected permissive App Transport Security configuration; HTTPS and ATS remain the preferred baseline.' },
644
651
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUncheckedSendableUsage, ruleId: 'heuristics.ios.unchecked-sendable.ast', code: 'HEURISTICS_IOS_UNCHECKED_SENDABLE_AST', message: 'AST heuristic detected @unchecked Sendable usage.' },
645
652
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftPreconcurrencyUsage, ruleId: 'heuristics.ios.preconcurrency.ast', code: 'HEURISTICS_IOS_PRECONCURRENCY_AST', message: 'AST heuristic detected @preconcurrency usage.' },
646
653
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNonisolatedUnsafeUsage, ruleId: 'heuristics.ios.nonisolated-unsafe.ast', code: 'HEURISTICS_IOS_NONISOLATED_UNSAFE_AST', message: 'AST heuristic detected nonisolated(unsafe) usage.' },
@@ -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, 50);
6
+ assert.equal(iosRules.length, 51);
7
7
 
8
8
  const ids = iosRules.map((rule) => rule.id);
9
9
  assert.deepEqual(ids, [
@@ -24,6 +24,7 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
24
24
  'heuristics.ios.dependencies.cocoapods.ast',
25
25
  'heuristics.ios.dependencies.carthage.ast',
26
26
  'heuristics.ios.security.userdefaults-sensitive-data.ast',
27
+ 'heuristics.ios.security.insecure-transport.ast',
27
28
  'heuristics.ios.unchecked-sendable.ast',
28
29
  'heuristics.ios.preconcurrency.ast',
29
30
  'heuristics.ios.nonisolated-unsafe.ast',
@@ -96,6 +97,10 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
96
97
  byId.get('heuristics.ios.security.userdefaults-sensitive-data.ast')?.then.code,
97
98
  'HEURISTICS_IOS_SECURITY_USERDEFAULTS_SENSITIVE_DATA_AST'
98
99
  );
100
+ assert.equal(
101
+ byId.get('heuristics.ios.security.insecure-transport.ast')?.then.code,
102
+ 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST'
103
+ );
99
104
  assert.equal(
100
105
  byId.get('heuristics.ios.preconcurrency.ast')?.then.code,
101
106
  'HEURISTICS_IOS_PRECONCURRENCY_AST'
@@ -307,6 +307,24 @@ export const iosRules: RuleSet = [
307
307
  code: 'HEURISTICS_IOS_SECURITY_USERDEFAULTS_SENSITIVE_DATA_AST',
308
308
  },
309
309
  },
310
+ {
311
+ id: 'heuristics.ios.security.insecure-transport.ast',
312
+ description: 'Detects insecure HTTP transport or permissive ATS configuration in iOS projects.',
313
+ severity: 'WARN',
314
+ platform: 'ios',
315
+ locked: true,
316
+ when: {
317
+ kind: 'Heuristic',
318
+ where: {
319
+ ruleId: 'heuristics.ios.security.insecure-transport.ast',
320
+ },
321
+ },
322
+ then: {
323
+ kind: 'Finding',
324
+ message: 'AST heuristic detected insecure iOS transport configuration; HTTPS and ATS remain the preferred baseline.',
325
+ code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST',
326
+ },
327
+ },
310
328
  {
311
329
  id: 'heuristics.ios.unchecked-sendable.ast',
312
330
  description: 'Detects @unchecked Sendable usage in iOS production code.',
@@ -87,6 +87,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
87
87
  'ios.security.userdefaults-sensitive-data',
88
88
  ['heuristics.ios.security.userdefaults-sensitive-data.ast']
89
89
  ),
90
+ 'skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto': heuristicDetector(
91
+ 'ios.security.insecure-transport',
92
+ ['heuristics.ios.security.insecure-transport.ast']
93
+ ),
90
94
  'skills.ios.no-unchecked-sendable': heuristicDetector('ios.unchecked-sendable', [
91
95
  'heuristics.ios.unchecked-sendable.ast',
92
96
  ]),
@@ -381,6 +381,13 @@ const normalizeKnownRuleTarget = (
381
381
  ) {
382
382
  return 'skills.ios.no-legacy-expectation-description';
383
383
  }
384
+ if (
385
+ includes('app transport security') ||
386
+ includes('ats https') ||
387
+ includes('https por defecto')
388
+ ) {
389
+ return 'skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto';
390
+ }
384
391
  if (
385
392
  includes('mixing legacy xctest style') ||
386
393
  includes('mixed xctest and swift testing') ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.196",
3
+ "version": "6.3.197",
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-13T11:03:09.894Z",
4
+ "generatedAt": "2026-05-13T11:13:04.662Z",
5
5
  "bundles": [
6
6
  {
7
7
  "name": "android-guidelines",
@@ -5764,7 +5764,7 @@
5764
5764
  "name": "ios-guidelines",
5765
5765
  "version": "1.0.0",
5766
5766
  "source": "file:vendor/skills/ios-enterprise-rules/SKILL.md",
5767
- "hash": "cadb9547991b6309ad35b1e503c6fafda8b655823e51b52023b037bac267c129",
5767
+ "hash": "d4504cef8996fd4877a6c89183ee891e33be0164628ec64d0e1d564db60f9a7a",
5768
5768
  "rules": [
5769
5769
  {
5770
5770
  "id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
@@ -5871,7 +5871,7 @@
5871
5871
  "sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
5872
5872
  "confidence": "MEDIUM",
5873
5873
  "locked": true,
5874
- "evaluationMode": "DECLARATIVE",
5874
+ "evaluationMode": "AUTO",
5875
5875
  "origin": "core"
5876
5876
  },
5877
5877
  {