Findings, with file and line
The three reviews of v0.1.44 (
d4f4292) condensed, with the file and line for each finding, so each session can go straight to the code. Read-only reviews; nothing was compiled.
Line numbers are from d4f4292. They move as fixes land.
Security
- S1 signatures not enforced (vault).
Packages/SGitVault/Sources/SGitVault/SGitVault.swift:33hasrequireSignatures = false, and nothing sets it to true. Lines 307–315 accept.unsigned,.legacy,.keyMissingand.invalid, and only log the result. Lines 438–452 read the public key frombare/keys/<id>in the same vault. Fix: always refuse.invalid. SetrequireSignatures = trueinVaultSession.makeReader(PrompTugal/Vault/VaultSession.swift:79-81) andopenAccount(:133-135). Pin the allowed author key ids per vault. - S2 data sent to the AI without consent (collab).
PrompTugal/AI/ChatStore.swift:89turns on agenda, picks and team context by default. "Current page" sends page text (AIContext.swift:141-148, 273-274). The only disclosure is about the key (AskView.swift:79, 347).where_is_everyoneshares teammates' plans (AITools.swift:25-27). - S3 silent Keychain fallback (vault).
PrompTugal/Vault/VaultKeychain.swift:110-125tries.faceID, then.userPresence, then.deviceUnlocked. The last option has no access control (:121). The Secure Enclave wrap also fails without a passcode (VaultKeyWrap.swift:258). The screen still says "behind Face ID" (VaultViews.swift~211). - S4 debug in release (design, platform).
PrompTugal/Design/Components.swift:252hasDebugMode.defaultOn = true.AskView.swift:13andLanesView.swift:9hard-codetrue.AppShell.swift:73-79ignoresdebugOnly.PrompTugal/Shell/WebPage.swift:92setsisInspectable = true. - S5 imported vault treated as yours (vault, collab).
VaultSession.swift:73-75falls back tovaults.first. Imported keys get the role "imported" (:87,CollabVaultGlue.swift:20-21).AIKeyStore.loadFromVault(AIKeyStore.swift:246-251) can then read an OpenRouter key from a teammate's vault. - S6 app-switcher snapshot (design, vault). Nothing hides sensitive screens when the app goes inactive. The key field is a
TextField(VaultViews.swift:144);TeamPlansView.swift:222shows how to do it with aSecureField. - S7 low.
- Inflate has no output cap (
Zlib.swift:21). NeitherVaultTransport.swift:132norHTTPClient.swift:96caps the body size. - The key stays on the pasteboard after paste-import (
VaultViews.swift:169). Ask's Copy uses the general pasteboard (AskView.swift:145). notify.plancan show the permission prompt without a tap (AppBridge.swift:174-177).schedule.getis open to both hosts (:159-160). The meter's "already" answer is trusted (:264-277).- Lane endpoints can be any https host (
LaneAddress.swift:72, 80). Append tokens are stored in UserDefaults (LanesStore.swift:66-68). - Links in Ask output are tappable (
AskView.swift:470-472). - Refunds are not reversed (
CreditStore.swift:95).
App Review
- R1 demo access (design, team).
- Who are you? lists real team names (
Dashboards/TodayView.swift:12-14, 33-49). - "Not on the team" ends on an empty Today tab (
TodayView.swift:15,Components.swift:336-338). - Sample data only turns on with a launch argument (
Shell/LaunchOptions.swift:20). - R3 privacy policy (editor, design).
website/pages/privacy.html:11and:17say nothing is collected or sent back. Lanes send data (Lanes/LaneClient.swift:26-58), and so do vault writes.:27says the OpenRouter key is behind Face ID, but it is storedAfterFirstUnlockThisDeviceOnly(AI/AIKeyStore.swift:56).- Speech may go to Apple (
Lanes/SpeechDictation.swift:37). - There is no privacy link in
Shell/SettingsView.swift. - R4 user content (collab, editor). Nothing in
Lanes/lets a person report or block.website/pages/support.html:53-60has no contact address. - R5 purchases (team).
Store/ReadingCreditView.swift:78says every page opens at any balance.- The pack
credit.5is 500 pence in the app (CreditStore.swift:19-20) but 0.99 inStore/PrompTugal.storekit. - Credit is only written into the website's local storage (
Bridge/AppBridge.swift:278-295,BridgeScripts.swift:172-193). - Purpose strings (platform).
NFCReaderUsageDescriptionexists, but there is no Core NFC code (project.pbxproj:603).- The camera is used only for QR codes (
Vault/VaultViews.swift:336). - The speech string should say that audio may go to Apple.
- Background modes (platform).
processingis inConfig/PrompTugal-Info.plist:26, but onlyBGAppRefreshTaskis used. - External payment (team).
- Only
buy.stripe.comand/account/top-up.htmlare intercepted (AppBridge.swift:107). WebPage.swift:129-135allows every other navigation.- Trademark (Dinis).
- The
ShortcutWebSummitimage set is the problem asset. - "Web Summit Lisbon" appears in
News/AgendaView.swift:31,App/PrompTugalApp.swift:198andSchedule/ScheduleIntents.swift:55. - AASA.
https://promptugal.news/.well-known/apple-app-site-associationreturns 404, soapplinks:andwebcredentials:do nothing. - Fine.
- The privacy manifest reasons (CA92.1, C617.1, DDA9.1) match the code.
- No downloaded code.
- The native work is well beyond a web wrapper.
- The Time Sensitive entitlement is justified.
ITSAppUsesNonExemptEncryption = NOis defensible.
Stability
- Q1 (team).
ScheduleDocument.swift:35-36accepts anyatvalue, and:135then runsInt64((t * 1000).rounded()), which traps on huge values. This is reachable through the bridge'sschedule.set(AppBridge.swift:163-168) and through vault picks. - Q2 (design).
GraphExplorerView.swift:61-68replaces the index but keepsselected,pathandpathStart, which are then used at lines 55, 196, 233 and 308.GraphModel.swift:78-80runsInt(Double)on JSON values.- Q3 (team).
CreditStore.swift:96-101callsfinish()even thoughMeterStore.save()(MeterStore.swift:130-138) swallows errors. - Q4 (collab).
LanesStoreis@MainActor(:6).makeMyLane(:141) generates the RSA-4096 key on it (LaneClient.swift:191-205). The inbox is also decrypted on it (:229-237). - Q5 (platform).
- There is no
#if DEBUGanywhere. LaunchOptions.swift:11-20is honoured in release.AppShell.swift:35persists-PTMe.PreviewSamples.swiftships in the release build..github/workflows/ios.yml:83builds Debug only.- The app targets use Swift 5 mode with complete concurrency checking, so data races are only warnings.
- Q6 (team).
ReminderScheduler.swift:64-71sets the delegate late, and theopenedURLit sets (:67) is never read. - Q7 (vault, collab).
String(describing: error)is shown to users (VaultViews.swift:231, 282, 319;VaultSession.swift:103, 116, 164).VaultErroris not aLocalizedError(VaultError.swift:4).- Q8.
- The team models exist three times:
TeamModels.swift:139,WireModels.swift:170andAIContext.swift:305-313. - TeamStore uses
URLSession.shared(TeamStore.swift:158-167). - Lisbon-day code is in
DayPlanner.swift:210,AIContext.swift:100andPrompTugalApp.swift:313. - The base URL is defined three times.
- Q9. Fixed widths:
LanesView.swift:30(400),WallView.swift:19(360),GraphExplorerView.swift:89(340) andWebsiteView.swift:20(250). - Smaller.
- Ask can double-send (
ChatStore.swift:164, 187). - A tap on the agent grid's header selects row 0 (
DashboardParts.swift:66). - Five fixed font sizes ignore Dynamic Type (
WallView.swift:79, among others). - The chat history is unbounded (
ChatStore.swift:133). VaultCommitBuilder.swift:184usesparts.last!.walkTreehas no depth cap.- Tests missing. AppBridge origin checks, CreditStore and MeterStore, VaultSession and VaultKeychain, GraphIndex, PlannerStore, ReminderScheduler, RemoteFeed, TeamStore.
- Fine.
- Few force unwraps, all guarded or on constants.
- No
print, no open markers and notry!in app code. - Logs are capped.
- Timers stop with their views.
- Heavy decoding, PBKDF2 and the graph layout already run off the main thread.