pumuki 6.3.323 → 6.3.325
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.
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
hasSwiftDummyAwaitUsage,
|
|
35
35
|
hasSwiftDispatchSemaphoreUsage,
|
|
36
36
|
collectSwiftLongAsyncOperationWithoutCancellationCheckLines,
|
|
37
|
+
collectSwiftAdHocLoggingLines,
|
|
37
38
|
hasSwiftAdHocLoggingUsage,
|
|
38
39
|
hasSwiftAlamofireUsage,
|
|
39
40
|
collectSwiftComposableArchitectureUsageLines,
|
|
@@ -174,6 +175,7 @@ import {
|
|
|
174
175
|
collectSwiftSensitiveLoggingLines,
|
|
175
176
|
hasSwiftSensitiveLoggingUsage,
|
|
176
177
|
hasSwiftSelfPrintChangesUsage,
|
|
178
|
+
collectSwiftInsecureTransportLines,
|
|
177
179
|
collectSwiftSensitiveUserDefaultsStorageLines,
|
|
178
180
|
hasSwiftSensitiveUserDefaultsStorageUsage,
|
|
179
181
|
hasSwiftInsecureTransportUsage,
|
|
@@ -1944,7 +1946,9 @@ logger.error("Refresh failed \\(refreshToken)")
|
|
|
1944
1946
|
`;
|
|
1945
1947
|
|
|
1946
1948
|
assert.equal(hasSwiftAdHocLoggingUsage(adHoc), true);
|
|
1949
|
+
assert.deepEqual(collectSwiftAdHocLoggingLines(adHoc), [2, 3, 4, 5, 6]);
|
|
1947
1950
|
assert.equal(hasSwiftAdHocLoggingUsage(structuredSafe), false);
|
|
1951
|
+
assert.deepEqual(collectSwiftAdHocLoggingLines(structuredSafe), []);
|
|
1948
1952
|
assert.equal(hasSwiftSensitiveLoggingUsage(sensitive), true);
|
|
1949
1953
|
assert.deepEqual(collectSwiftSensitiveLoggingLines(sensitive), [2, 3]);
|
|
1950
1954
|
assert.equal(hasSwiftSensitiveLoggingUsage(structuredSafe), false);
|
|
@@ -2077,8 +2081,11 @@ let text = "https://example.com/catalog.json"
|
|
|
2077
2081
|
`;
|
|
2078
2082
|
|
|
2079
2083
|
assert.equal(hasSwiftInsecureTransportUsage(source), true);
|
|
2084
|
+
assert.deepEqual(collectSwiftInsecureTransportLines(source), [4]);
|
|
2080
2085
|
assert.equal(hasSwiftInsecureTransportUsage(plist), true);
|
|
2086
|
+
assert.deepEqual(collectSwiftInsecureTransportLines(plist), [5]);
|
|
2081
2087
|
assert.equal(hasSwiftInsecureTransportUsage(ignored), false);
|
|
2088
|
+
assert.deepEqual(collectSwiftInsecureTransportLines(ignored), []);
|
|
2082
2089
|
});
|
|
2083
2090
|
|
|
2084
2091
|
test('detector iOS de localización detecta strings UI hardcodeadas sin confundir keys ni comentarios', () => {
|
|
@@ -1617,10 +1617,14 @@ export const collectSwiftMagicNumberLayoutLines = (source: string): readonly num
|
|
|
1617
1617
|
};
|
|
1618
1618
|
|
|
1619
1619
|
export const hasSwiftAdHocLoggingUsage = (source: string): boolean => {
|
|
1620
|
+
return collectSwiftAdHocLoggingLines(source).length > 0;
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1623
|
+
export const collectSwiftAdHocLoggingLines = (source: string): readonly number[] => {
|
|
1620
1624
|
return collectSwiftRegexLines(
|
|
1621
1625
|
source,
|
|
1622
1626
|
/\b(?:print|debugPrint|dump|NSLog|os_log)\s*\(/
|
|
1623
|
-
)
|
|
1627
|
+
);
|
|
1624
1628
|
};
|
|
1625
1629
|
|
|
1626
1630
|
export const hasSwiftSensitiveLoggingUsage = (source: string): boolean => {
|
|
@@ -1733,22 +1737,39 @@ export const collectSwiftSensitiveUserDefaultsStorageLines = (source: string): r
|
|
|
1733
1737
|
};
|
|
1734
1738
|
|
|
1735
1739
|
export const hasSwiftInsecureTransportUsage = (source: string): boolean => {
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
+
return collectSwiftInsecureTransportLines(source).length > 0;
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
export const collectSwiftInsecureTransportLines = (source: string): readonly number[] => {
|
|
1744
|
+
const lines = source.split(/\r?\n/);
|
|
1745
|
+
const result: number[] = [];
|
|
1746
|
+
let pendingAtsKeyLine: number | null = null;
|
|
1747
|
+
|
|
1748
|
+
lines.forEach((line, index) => {
|
|
1749
|
+
const lineNumber = index + 1;
|
|
1750
|
+
const sanitized = stripSwiftLineForSemanticScan(line);
|
|
1751
|
+
if (!/^\s*\/\//.test(line) && /["']http:\/\/[^"']*["']/.test(line)) {
|
|
1752
|
+
result.push(lineNumber);
|
|
1740
1753
|
}
|
|
1741
|
-
return /["']http:\/\/[^"']*["']/.test(line);
|
|
1742
|
-
});
|
|
1743
1754
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1755
|
+
if (/\bNSAllowsArbitraryLoads\b\s*=\s*(?:true|YES|1)\b/i.test(sanitized)) {
|
|
1756
|
+
result.push(lineNumber);
|
|
1757
|
+
pendingAtsKeyLine = null;
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1747
1760
|
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1761
|
+
if (/<key>\s*NSAllowsArbitraryLoads\s*<\/key>/i.test(line)) {
|
|
1762
|
+
pendingAtsKeyLine = lineNumber;
|
|
1763
|
+
return;
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
if (pendingAtsKeyLine !== null && /<true\s*\/>/i.test(line)) {
|
|
1767
|
+
result.push(pendingAtsKeyLine);
|
|
1768
|
+
pendingAtsKeyLine = null;
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
|
|
1772
|
+
return sortedUniqueLines(result);
|
|
1752
1773
|
};
|
|
1753
1774
|
|
|
1754
1775
|
const swiftUiLiteralTextPatterns = [
|
|
@@ -804,15 +804,15 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
804
804
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNonIBOutletImplicitlyUnwrappedOptionalUsage, ruleId: 'heuristics.ios.safety.non-iboutlet-iuo.ast', code: 'HEURISTICS_IOS_SAFETY_NON_IBOUTLET_IUO_AST', message: 'AST heuristic detected an implicitly unwrapped optional outside IBOutlet wiring; explicit optionals or initialization guarantees remain the preferred baseline.' },
|
|
805
805
|
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftMagicNumberLayoutUsage, locateLines: TextIOS.collectSwiftMagicNumberLayoutLines, primaryNode: (lines) => ({ kind: 'call', name: 'SwiftUI layout numeric literal', lines }), relatedNodes: (lines) => [{ kind: 'property', name: 'replacement: named metric constant or design token', lines }], why: 'Inline numeric layout literals hide design intent and make visual remediation dependent on scanning the whole view body.', impact: 'Pixel-perfect slices can be blocked without a concrete node unless the finding points to the exact spacing, frame or padding call to fix.', expected_fix: 'Move repeated or meaningful layout numbers into named constants or design tokens, or use relative layout APIs when the number encodes screen geometry.', ruleId: 'heuristics.ios.maintainability.magic-number-layout.ast', code: 'HEURISTICS_IOS_MAINTAINABILITY_MAGIC_NUMBER_LAYOUT_AST', message: 'AST heuristic detected SwiftUI layout magic numbers; named constants or design tokens remain the preferred baseline.' },
|
|
806
806
|
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUIKitManualFrameLayoutUsage, locateLines: TextIOS.collectSwiftUIKitManualFrameLayoutLines, primaryNode: (lines) => ({ kind: 'call', name: 'UIKit manual frame CGRect layout', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: Auto Layout constraints or SwiftUI relative layout', lines }], why: 'Manual UIKit frames hard-code geometry instead of using Auto Layout constraints or SwiftUI relative layout, so the layout cannot adapt reliably to devices, Dynamic Type or localization.', impact: 'Pixel-perfect work can regress across screens because fixed CGRect values bypass constraint solving and produce file-level ambiguity unless the exact frame node is reported.', expected_fix: 'Replace UIView(frame: CGRect(...)) and .frame = CGRect(...) layout with Auto Layout anchors/NSLayoutConstraint, UIStackView constraints, or SwiftUI relative layout where the screen is SwiftUI-first.', ruleId: 'heuristics.ios.uikit.manual-frame-layout.ast', code: 'HEURISTICS_IOS_UIKIT_MANUAL_FRAME_LAYOUT_AST', message: 'AST heuristic detected UIKit manual frame layout; use Auto Layout constraints or SwiftUI relative layout.' },
|
|
807
|
-
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAdHocLoggingUsage, ruleId: 'heuristics.ios.logging.adhoc-print.ast', code: 'HEURISTICS_IOS_LOGGING_ADHOC_PRINT_AST', message: 'AST heuristic detected
|
|
807
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAdHocLoggingUsage, locateLines: TextIOS.collectSwiftAdHocLoggingLines, primaryNode: (lines) => ({ kind: 'call', name: 'ad-hoc iOS logging call', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: structured logger with approved privacy level', lines }], why: 'Production iOS code must not use print/debugPrint/dump/NSLog/os_log ad hoc calls because they bypass repository logging policy and privacy controls.', impact: 'Ad-hoc logs create noisy diagnostics, can leak runtime state, and leave the developer without a clear logging boundary to audit or disable by environment.', expected_fix: 'Remove the print/debugPrint/dump/NSLog/os_log call or replace it with the repository-approved structured logger. If the log is still needed, use an explicit privacy level and avoid user data, tokens and request payloads.', ruleId: 'heuristics.ios.logging.adhoc-print.ast', code: 'HEURISTICS_IOS_LOGGING_ADHOC_PRINT_AST', message: 'AST heuristic detected ad-hoc logging in iOS production code.' },
|
|
808
808
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftSensitiveLoggingUsage, locateLines: TextIOS.collectSwiftSensitiveLoggingLines, primaryNode: (lines) => ({ kind: 'call', name: 'logging call with sensitive data', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: redacted structured log without token/password/email/userId', lines }], why: 'Production logs must not include tokens, credentials, emails or user identifiers because logs are copied to diagnostics, crash reports and external observability stores.', impact: 'Sensitive values can leak outside the device or backend trust boundary and make incident response depend on scrubbing historical logs.', expected_fix: 'Remove the sensitive value from the log, log a redacted marker, or emit structured metadata that cannot expose token, password, email, authorization or userId values.', ruleId: 'heuristics.ios.logging.sensitive-data.ast', code: 'HEURISTICS_IOS_LOGGING_SENSITIVE_DATA_AST', message: 'AST heuristic detected sensitive data in an iOS logging call.' },
|
|
809
809
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftHardcodedSensitiveStringUsage, locateLines: TextIOS.collectSwiftHardcodedSensitiveStringLines, primaryNode: (lines) => ({ kind: 'property', name: 'hardcoded sensitive Swift string', lines }), relatedNodes: (lines) => [{ kind: 'property', name: 'replacement: Keychain, secure config or environment-specific secret source', lines }], why: 'Sensitive strings assigned directly to token/password/secret properties create static production secrets and cannot be rotated safely.', impact: 'Credentials or identifiers can leak through source, binaries, logs or screenshots and block release until the concrete assignment is removed.', expected_fix: 'Read sensitive values from Keychain, secure configuration, injected environment or a repository-approved secret provider. Keep user-facing copy in localization assets, not sensitive variables.', ruleId: 'heuristics.ios.security.hardcoded-sensitive-string.ast', code: 'HEURISTICS_IOS_SECURITY_HARDCODED_SENSITIVE_STRING_AST', message: 'AST heuristic detected hardcoded sensitive Swift string; Keychain, secure config or environment-specific secrets remain the preferred baseline.' },
|
|
810
810
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUnlocalizedDateFormatterUsage, ruleId: 'heuristics.ios.localization.unlocalized-dateformatter.ast', code: 'HEURISTICS_IOS_LOCALIZATION_UNLOCALIZED_DATEFORMATTER_AST', message: 'AST heuristic detected DateFormatter dateFormat usage without an explicit locale.' },
|
|
811
811
|
{ 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.' },
|
|
812
812
|
{ 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.' },
|
|
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
|
-
{ 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
|
|
815
|
-
{ 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
|
|
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: 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
816
|
{ 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
817
|
{ 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.' },
|
|
818
818
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftHardcodedUiStringUsage, locateLines: TextIOS.collectSwiftHardcodedUiStringLines, primaryNode: (lines) => ({ kind: 'property', name: 'hardcoded user-facing SwiftUI string', lines }), relatedNodes: (lines) => [{ kind: 'property', name: 'replacement: String Catalog key or String(localized:)', lines }], why: 'User-facing literals in SwiftUI code bypass String Catalogs and make localization drift invisible.', impact: 'A consumer slice can be blocked without knowing which text literal must move to localization assets.', expected_fix: 'Move visible copy to String Catalogs or use repository-approved localized string keys; keep only localization keys in SwiftUI code.', ruleId: 'heuristics.ios.localization.hardcoded-ui-string.ast', code: 'HEURISTICS_IOS_LOCALIZATION_HARDCODED_UI_STRING_AST', message: 'AST heuristic detected hardcoded user-facing SwiftUI text; String(localized:) and String Catalogs remain the preferred baseline.' },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.325",
|
|
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": {
|