pumuki 6.3.328 → 6.3.329
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.
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
collectSwiftAdHocLoggingLines,
|
|
38
38
|
hasSwiftAdHocLoggingUsage,
|
|
39
39
|
hasSwiftAlamofireUsage,
|
|
40
|
+
collectSwiftAlamofireLines,
|
|
40
41
|
collectSwiftComposableArchitectureUsageLines,
|
|
41
42
|
hasSwiftEmptyCatchUsage,
|
|
42
43
|
collectSwiftNSErrorThrowLines,
|
|
@@ -182,6 +183,7 @@ import {
|
|
|
182
183
|
hasSwiftSensitiveUserDefaultsStorageUsage,
|
|
183
184
|
hasSwiftInsecureTransportUsage,
|
|
184
185
|
hasSwiftJSONSerializationUsage,
|
|
186
|
+
collectSwiftJSONSerializationLines,
|
|
185
187
|
hasSwiftExplicitColorStaticMemberUsage,
|
|
186
188
|
hasSwiftClosureBasedViewBuilderContentUsage,
|
|
187
189
|
collectSwiftForceUnwrapLines,
|
|
@@ -2042,8 +2044,12 @@ final class APIClient {
|
|
|
2042
2044
|
|
|
2043
2045
|
assert.equal(hasSwiftAlamofireUsage(source), true);
|
|
2044
2046
|
assert.equal(hasSwiftJSONSerializationUsage(source), true);
|
|
2047
|
+
assert.deepEqual(collectSwiftAlamofireLines(source), [2, 6]);
|
|
2048
|
+
assert.deepEqual(collectSwiftJSONSerializationLines(source), [7]);
|
|
2045
2049
|
assert.equal(hasSwiftAlamofireUsage(ignored), false);
|
|
2046
2050
|
assert.equal(hasSwiftJSONSerializationUsage(ignored), false);
|
|
2051
|
+
assert.deepEqual(collectSwiftAlamofireLines(ignored), []);
|
|
2052
|
+
assert.deepEqual(collectSwiftJSONSerializationLines(ignored), []);
|
|
2047
2053
|
});
|
|
2048
2054
|
|
|
2049
2055
|
test('detector iOS de seguridad detecta secretos en UserDefaults y AppStorage', () => {
|
|
@@ -1758,15 +1758,23 @@ export const hasSwiftUnlocalizedDateFormatterUsage = (source: string): boolean =
|
|
|
1758
1758
|
return false;
|
|
1759
1759
|
};
|
|
1760
1760
|
|
|
1761
|
+
export const collectSwiftAlamofireLines = (source: string): readonly number[] => {
|
|
1762
|
+
return sortedUniqueLines([
|
|
1763
|
+
...collectSwiftRegexLines(source, /^\s*import\s+Alamofire\b/),
|
|
1764
|
+
...collectSwiftRegexLines(source, /\b(?:AF|Alamofire)\s*\.\s*request\b/),
|
|
1765
|
+
]);
|
|
1766
|
+
};
|
|
1767
|
+
|
|
1761
1768
|
export const hasSwiftAlamofireUsage = (source: string): boolean => {
|
|
1762
|
-
return (
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1769
|
+
return collectSwiftAlamofireLines(source).length > 0;
|
|
1770
|
+
};
|
|
1771
|
+
|
|
1772
|
+
export const collectSwiftJSONSerializationLines = (source: string): readonly number[] => {
|
|
1773
|
+
return collectSwiftRegexLines(source, /\bJSONSerialization\s*\./);
|
|
1766
1774
|
};
|
|
1767
1775
|
|
|
1768
1776
|
export const hasSwiftJSONSerializationUsage = (source: string): boolean => {
|
|
1769
|
-
return
|
|
1777
|
+
return collectSwiftJSONSerializationLines(source).length > 0;
|
|
1770
1778
|
};
|
|
1771
1779
|
|
|
1772
1780
|
export const hasSwiftSensitiveUserDefaultsStorageUsage = (source: string): boolean => {
|
|
@@ -808,8 +808,8 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
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
|
-
{ 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
|
-
{ 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.' },
|
|
811
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAlamofireUsage, locateLines: TextIOS.collectSwiftAlamofireLines, primaryNode: (lines) => ({ kind: 'call', name: 'Alamofire import or request call', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: native URLSession networking boundary', lines }], why: 'iOS production networking should use the native URLSession boundary unless the repository explicitly approves a third-party networking dependency.', impact: 'Third-party networking calls create a separate policy surface for retries, cancellation, privacy and observability, and whole-file findings are not actionable during consumer remediation.', expected_fix: 'Replace Alamofire imports and AF/Alamofire request calls with the repository-approved URLSession client or a native networking adapter.', 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
|
+
{ 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
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.' },
|
package/core/facts/index.test.ts
CHANGED
|
@@ -134,3 +134,46 @@ final class CartViewModel {
|
|
|
134
134
|
assert.deepEqual(match.primary_node?.lines, [5]);
|
|
135
135
|
assert.match(match.expected_fix ?? '', /\[weak self\]/i);
|
|
136
136
|
});
|
|
137
|
+
|
|
138
|
+
test('extractHeuristicFacts emite networking iOS con lineas y remediation accionable', () => {
|
|
139
|
+
const params: HeuristicExtractionParams = {
|
|
140
|
+
facts: [
|
|
141
|
+
{
|
|
142
|
+
kind: 'FileContent',
|
|
143
|
+
source: 'repo',
|
|
144
|
+
path: 'apps/ios/Infrastructure/Networking/BuyerAPIClient.swift',
|
|
145
|
+
content: `
|
|
146
|
+
import Alamofire
|
|
147
|
+
|
|
148
|
+
final class BuyerAPIClient {
|
|
149
|
+
func load() {
|
|
150
|
+
AF.request("https://api.example.com")
|
|
151
|
+
let object = try? JSONSerialization.jsonObject(with: Data())
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
`,
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
detectedPlatforms: {
|
|
158
|
+
ios: { detected: true, confidence: 'HIGH' },
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const extractedFacts = extractHeuristicFacts(params);
|
|
163
|
+
const alamofire = extractedFacts.find(
|
|
164
|
+
(fact) => fact.ruleId === 'heuristics.ios.networking.alamofire.ast'
|
|
165
|
+
);
|
|
166
|
+
const jsonSerialization = extractedFacts.find(
|
|
167
|
+
(fact) => fact.ruleId === 'heuristics.ios.json.jsonserialization.ast'
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
assert.ok(alamofire);
|
|
171
|
+
assert.deepEqual(alamofire.lines, [2, 6]);
|
|
172
|
+
assert.deepEqual(alamofire.primary_node?.lines, [2, 6]);
|
|
173
|
+
assert.match(alamofire.expected_fix ?? '', /URLSession/i);
|
|
174
|
+
|
|
175
|
+
assert.ok(jsonSerialization);
|
|
176
|
+
assert.deepEqual(jsonSerialization.lines, [7]);
|
|
177
|
+
assert.deepEqual(jsonSerialization.primary_node?.lines, [7]);
|
|
178
|
+
assert.match(jsonSerialization.expected_fix ?? '', /Codable/i);
|
|
179
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.329",
|
|
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": {
|