feat(mobile): harden bootstrap, routing, and release gates (w6b) - #5421
Merged
Conversation
Export SECURITY_COMMAND_TYPES as the shared tuple and derive SecurityCommandType from it. Add an app-shared invalidation-scope test and an apps/web drift test asserting the db union matches the shared tuple. Type the web create-call literals and the SecurityAgentAdmissionAction redeclaration with the shared type.
Add an additive security_lifecycle variant to pushDataSchema with an eight-value event enum mapped 1:1 to SecurityAuditLogAction. Route the variant to the existing security channel and add lifecycle lock-screen copy in both exhaustive presentation switches.
… review Extend SECURITY_INTENTS to the four command intents with an authority-linked SECURITY_INTENT_FOR_COMMAND_TYPE map. Add the code_review_settled terminal event with a privacy-minimal schema and add the code_review operation ledger domain.
Add an Explore section with Code Reviewer, Security Agent, and PR Review rows so an empty or erroring Home still offers an outcome-led first action. Scope resolves as organizationId or the personal security scope; PR Review stays feature-flag gated.
Add getCommandStatuses on the personal and org routers with a min(1).max(100) uuid-array input schema. Batch-fetch owner-scoped commands, omit unknown or foreign ids, and settle terminal commands through the existing ledger settle helper. Keep getCommandStatus for older mobile clients.
Require ORGANIZATION_BILLING_ROLES when an org already has a GitLab integration, on both the OAuth connect and callback paths; first-time connect keeps member access. Add a role matrix over every organization-security-agent procedure and map access denials to permission-specific error codes instead of connection errors.
Extend the notification preferences getter with a capabilities map for the seven category keys, computing availability from organization membership, enabled Security config, and KiloClaw instances.
…ions Narrow the security findings list, code reviews list, and organization list responses so heavy content is fetched only by detail procedures. The findings list nulls raw_data after decoration; the code reviews list drops council_result, manual_config, and previous_summary_body; the organization list selects explicit columns. Each narrowing ships with a response-width test and a detail-preserved test.
Emit analysis_* and remediation_* lifecycle pushes from post-commit, env-holding sites in the security-auto-analysis service. The web internal notifications route accepts a lifecycle body and dispatches push only; the notifications worker gains a security_lifecycle dispatch kind gated on securityFindingsEnabled. Terminal emits fire only when the persist actually made the attempt terminal.
Map only an unmatched gitUrl to Connect repository and a matched repo with an unresolved model to Back to sessions. Set persistent retry guidance on repository fetch failure. Open GitHub integration setup instead of the expired repo-picker and clear terminal guidance after the Connect action runs. Cover the Connect action with a unit test.
…tus bar Replace the half-height scrim sheet with an opaque full-window Modal. The surface pads the top safe-area inset, so the content clears the system status bar. iOS keeps the native pageSheet.
The next line already discards the Android detent on iOS, so the guard changed nothing.
The layer covered the session while the transparent Android Modal slid out. The Modal is now opaque and full height, so the cover is dead weight. Three recorded Back dismissals show no white frame without it.
…viewer-6304 # Conflicts: # services/cloud-agent-next/src/session/session-registration.ts # services/session-ingest/src/dos/SessionIngestDO.test.ts # services/session-ingest/src/dos/SessionIngestDO.ts
…' into audit-w6b-bootstrap-release-ff5f
iscekic
enabled auto-merge (squash)
August 24, 2026 16:34
…elease-ff5f Main carries the merged w6a (#5428), which moved the remediation ledger admit into the Worker before the queue hand-off. Take main for every conflicted security file and drop the stale web-side admit in the retry handler.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Home screen now shows an Explore area with three shortcuts: Code Reviewer, Security Agent, and PR Review. The area stays visible when the session list is loading, empty, filled, or failed to load.
The Profile screen now paints first and loads account and organization details only after the screen transition settles, showing placeholders while it waits.
Opening a link with a broken review, session, or organization identifier now shows a not-found screen with a back action instead of a blank or broken screen.
The production host allowlist is now complete. It holds all seven production hosts from the committed environment file, including the three
kiloapps.ioendpoints, and a unit test reads that file and asserts every URL value passes the scheme and host checks, so a missing host fails before any build. A production build still fails on a missing required value, a wrong scheme, an off-allowlist host, or a missing Sentry source-map token.Files
apps/mobile/src/lib/url-contract.js— new; holdsURL_SCHEMES,PRODUCTION_HOSTS,assertUrlScheme, andassertProductionHost; the allowlist now lists all seven production hosts.apps/mobile/app.config.ts— applies the scheme and host checks; makes missing env fatal in production; adds the Sentry token gate; bakesextra.isProductionBuild.apps/mobile/src/lib/config.ts— applies the scheme check at runtime and the production host check whenextra.isProductionBuildis true.The root layout now derives its bootstrap routing and its render gating from one pure resolver instead of two hand-kept copies, so the routing effect and the visibility flags can no longer disagree. The resolver returns a closed union of routing tags plus the error, redirect, and hidden flags, and the routing effect switches over the tag. The old inline if-chain and the old inline gating derivations are deleted; behavior stays the same.
Files
apps/mobile/src/lib/bootstrap-decision.ts— new; exports the input, decision, and tag types and the pure resolver.apps/mobile/src/app/_layout.tsx— calls the resolver in the routing effect and the render gate; replaces the inline if-chain with a switch.The release workflow pins EAS CLI to 21.8.0 and splits the old build-and-submit step into a preflight job, a build job, an artifact download, an inspection step, and separate iOS and Android submissions. The preflight fails closed when the EAS production environment misses a required value or the config contract fails. The build no longer uses
--auto-submit; submission runs from downloaded artifacts after inspection.Files
.github/workflows/kilo-app-release.yml— pins the CLI, adds the preflight job, splits build and submit, adds download and inspection steps.apps/mobile/eas.json— pinscli.versionto 21.8.0.apps/mobile/package.json— pins every eas-cli script to 21.8.0 and adds theassert:configscript.A new preflight script runs the fully evaluated Expo config and fails when the bundle id, package, scheme, associated domain, blocked permissions, Sentry plugin, or any required extra value violates the contract. The preflight invokes it inside the EAS production environment, so config drift fails before any build.
Files
apps/mobile/scripts/assert-expo-config.mjs— new; runsexpo config --jsonand checks the contract values.A new inspection script validates the EAS build result and the signed IPA and AAB before submission, and submission stops when an artifact violates a bundle, permission, endpoint, or debug-symbol contract. The IPA is checked for its bundle id, privacy manifest, usage descriptions, and SKAdNetwork endpoints; the AAB is checked for its package, blocked permissions, cleartext traffic, intent-filter host, and debug symbols.
Files
scripts/inspect-mobile-artifacts.mjs— new; validates build.json, inspects the IPA and AAB, and checks debug symbols.The home screen gains an Explore section with Code Reviewer, Security Agent, and PR Review rows, and the PR Review row stays behind the existing PR Review feature flag. The section renders in the empty, populated, and error states of the session list, so the shortcuts remain available when sessions fail to load.
Files
apps/mobile/src/components/home/product-choices.tsx— new; three rows, PR Review gated by the flag.apps/mobile/src/components/home/home-screen.tsx— renders ProductChoices after the sessions/promo branch.The profile screen defers its two mount-time queries until the navigation transition settles, using a new
useAfterInteractionshook, so the screen paints before the account and organization fetches start. The skeleton, stale, and error states stay, and the linked-accounts section now shows its skeleton while the interactions are pending.Files
apps/mobile/src/lib/hooks/use-after-interactions.ts— new; returns false on mount, then true afterInteractionManager.runAfterInteractions.apps/mobile/src/components/profile-screen.tsx— gates both queries on the hook and keeps the skeleton and error states.Six routes that read a required path parameter now parse it with
parseParamand renderInvalidRouteStatewith a bounded back target when the parameter is missing or malformed. Optional parameters keep their existing first-element unwrapping, and the session route no longer fires its query for a null session id.Files
apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.tsx— parses scope; renders InvalidRouteState.apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.tsx— parses scope; renders InvalidRouteState.apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].tsx— parses scope and id; back target depends on scope.apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.tsx— parses scope; renders InvalidRouteState.apps/mobile/src/app/(app)/(tabs)/(3_profile)/organization/member-limit.tsx— parses memberId; renders InvalidRouteState.apps/mobile/src/app/(app)/agent-chat/[session-id].tsx— parses session-id; disables the query and renders InvalidRouteState when null.Tests: 13 test files added or updated.
Generated: none.
Verification
Two cases ran on iOS across two verification rounds.
No round reproduced a defect on the unfixed build.
Recording:
ev03-coldstart.mp4shows the EV-03 cold launch from force-quit to interactive Home.Visual Changes
Home screen. The user now sees an Explore section on Home with rows for Code Reviewer, Security Agent, and PR Review. In the picture, the EXPLORE header and the three rows sit below the Kilo Agents card and above the tab bar.
Invalid-route screen. The user now gets a bounded not-found state with a back action when a route param is malformed. No picture shows this change. The single candidate shows the session not-found state after a malformed deep link; no deep link yields a malformed param on the device, so the picture fails to show the new InvalidRouteState with Page not found and Go back. The co-located route tests prove that state instead.
Reviewer Notes
Human steps:
apps/mobile/.envhosts before the first real production build; the release preflight fails closed on any mismatch. (after merge)SENTRY_AUTH_TOKENin the EAS production environment with non-secret visibility (plainorsensitive). (after merge)EXPO_PUBLIC_SENTRY_ENVIRONMENT=productionin the EAS production environment; the release preflight asserts it. The EAS preview environment no longer needsEXPO_PUBLIC_SENTRY_ENVIRONMENT=previewto avoid a crash, because the runtime host check now keys off the baked build intent. (after merge)PrivacyInfo.xcprivacyor the AAB may lack debug-symbols metadata; the follow-up fix is named in the plan. (after merge)Info.plistis parsed withpython3 plistlib; the release runner must providepython3. (after merge)Notes: E2E: the follow-up commit 13f4d4b adds three production hosts to the build-time allowlist and a unit test; the host check only runs in production builds, so it has no runtime behavior to verify. The existing iOS verification still holds.