Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "controller/termux-core/termux-source"]
path = controller/termux-core/termux-source
url = https://github.com/iiab/termux-app.git
url = https://github.com/appdevforall/termux-app.git
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.iiab.controller;

import android.util.Log;

import com.termux.shared.termux.extrakeys.ExtraKeysConstants;
import com.termux.shared.termux.extrakeys.ExtraKeysInfo;
import com.termux.shared.termux.extrakeys.ExtraKeysView;

import org.json.JSONException;

/**
* IIAB default extra-keys layout for the embedded Termux terminal.
*
* <p>This logic previously lived as {@code loadIIABDefaultKeys()} added directly to the
* vendored upstream class {@code ExtraKeysView} (in the {@code termux-source} submodule).
* It only uses public Termux APIs ({@link ExtraKeysView#reload(ExtraKeysInfo, float)} and
* the public {@link ExtraKeysInfo} constructor), so it now lives in the app instead. That
* keeps the Termux fork a clean mirror of upstream and avoids merge conflicts on every
* upstream sync (see {@code controller/docs/FORK_DELTA_ANALYSIS.md}, finding K1).
*/
public final class IIABExtraKeys {

private static final String TAG = "IIAB-ExtraKeys";

/**
* Two-row extra-keys layout. These keys must stay in sync with the keys handled by
* {@code MainActivity}'s {@code IExtraKeysView} click listener. Single source of truth.
*/
public static final String DEFAULT_LAYOUT =
"[\n" +
" ['ESC', '/', '-', 'HOME', 'UP', 'END', 'PGUP'],\n" +
" ['TAB', 'CTRL', 'ALT', 'LEFT', 'DOWN', 'RIGHT', 'PGDN']\n" +
"]";

/**
* Minimal one-row layout applied only if {@link #DEFAULT_LAYOUT} fails to load, so the
* user still gets usable keys instead of none (finding K4).
*/
static final String FALLBACK_LAYOUT =
"[['ESC', 'TAB', 'CTRL', 'LEFT', 'DOWN', 'UP', 'RIGHT']]";

private IIABExtraKeys() {
// Utility class — no instances.
}

/**
* Loads the IIAB default extra-keys layout into the given view via the public
* {@link ExtraKeysView#reload(ExtraKeysInfo, float)} API. If the default layout fails
* for any reason it falls back to {@link #FALLBACK_LAYOUT} so the terminal still shows
* usable keys. No-op if the view is null.
*
* @param extraKeysView the terminal's extra-keys view
*/
public static void apply(ExtraKeysView extraKeysView) {
if (extraKeysView == null) {
return;
}
if (tryLoad(extraKeysView, DEFAULT_LAYOUT)) {
return;
}
Log.w(TAG, "IIAB default extra-keys layout failed to load; applying minimal fallback");
if (tryLoad(extraKeysView, FALLBACK_LAYOUT)) {
return;
}
Log.e(TAG, "Both IIAB and fallback extra-keys layouts failed to load; no extra keys applied");
}

private static boolean tryLoad(ExtraKeysView extraKeysView, String layout) {
try {
extraKeysView.reload(buildInfo(layout), 0f);
return true;
} catch (Exception e) {
Log.e(TAG, "Failed to load extra-keys layout", e);
return false;
}
}

/**
* Builds an {@link ExtraKeysInfo} from a layout string using the same parameters as
* {@link #apply}. Package-private so unit tests can validate {@link #DEFAULT_LAYOUT}
* and {@link #FALLBACK_LAYOUT} without needing an Android view (finding K5).
*
* @param layout the extra-keys layout string
* @return the parsed {@link ExtraKeysInfo}
* @throws JSONException if the layout string is malformed
*/
static ExtraKeysInfo buildInfo(String layout) throws JSONException {
return new ExtraKeysInfo(
layout,
"default",
new ExtraKeysConstants.ExtraKeyDisplayMap());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2033,7 +2033,7 @@ public void logStackTrace(String tag, Exception e) {
findViewById(R.id.extra_keys_view);

if (extraKeysView != null) {
extraKeysView.loadIIABDefaultKeys();
IIABExtraKeys.apply(extraKeysView);

// Listen for normal keys (ESC, TAB, UP, etc)
extraKeysView.setExtraKeysViewClient(new com.termux.shared.termux.extrakeys.ExtraKeysView.IExtraKeysView() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.iiab.controller;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import com.termux.shared.termux.extrakeys.ExtraKeysInfo;

import org.junit.Test;

/**
* Unit tests for {@link IIABExtraKeys} (finding K5). These validate that the layout
* constants parse into the intended grid shape, catching a malformed layout edit before
* it ships. Runs on the plain JVM via {@code testOptions.unitTests.returnDefaultValues}
* + the {@code org.json} test dependency added in Phase 0.
*
* <p>Assertions are limited to grid structure (rows × keys), which is the part most likely
* to break on a bad edit and is independent of Android framework stubs.
*/
public class IIABExtraKeysTest {

@Test
public void defaultLayout_parsesIntoTwoRowsOfSevenKeys() throws Exception {
ExtraKeysInfo info = IIABExtraKeys.buildInfo(IIABExtraKeys.DEFAULT_LAYOUT);
assertNotNull(info);
assertEquals("default layout should have 2 rows", 2, info.getMatrix().length);
assertEquals("row 1 should have 7 keys", 7, info.getMatrix()[0].length);
assertEquals("row 2 should have 7 keys", 7, info.getMatrix()[1].length);
}

@Test
public void fallbackLayout_parsesIntoSingleRowOfSevenKeys() throws Exception {
ExtraKeysInfo info = IIABExtraKeys.buildInfo(IIABExtraKeys.FALLBACK_LAYOUT);
assertNotNull(info);
assertEquals("fallback layout should have 1 row", 1, info.getMatrix().length);
assertEquals("fallback row should have 7 keys", 7, info.getMatrix()[0].length);
}
}
21 changes: 20 additions & 1 deletion controller/docs/TECH_DEBT_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

> Consolidated, English-language successor to `controller/TECH_DEBT_AUDIT.md` (previously Spanish). Produced from four parallel line-level audits — UI/lifecycle, deploy/install, sync/ADB, and monitoring + build/infra. Scope: 34 Java files, ~11,707 LOC under `app/src/main/java/org/iiab/controller/`. Date: 2026-06-16. Repo status: proof-of-concept. See `docs/ARCHITECTURE.md` for how the module works.

## Progress log

_Last updated: 2026-06-16. Tracks remediation work against the findings below. IDs map to the register in this file (F/D/S/M) and to `FORK_DELTA_ANALYSIS.md` (K)._

**Phase 0 — Guardrails: DONE** (PR `chore/phase0-guardrails`)
- Extracted `SystemStatsUtil` and added the first JVM unit tests (`SystemStatsUtilTest`, `SyncHandshakeHelperTest`); added unit-test infra (`returnDefaultValues` + real `org.json`). Addresses **M10**.
- CI gate: blocking `testDebugUnitTest`; `:app:lintDebug` runs non-blocking (scoped to `:app`). Addresses **M11**.
- Added a root `.gitignore` and `FORK_DELTA_ANALYSIS.md`.
- Remaining: flip lint `abortOnError=true` once the `:app` lint backlog is triaged; broaden tests to more pure functions (`LogManager.getFormattedSize`, `InstallationPlanner` sizing, the YAML parser).

**K1 — Fork delta (Termux ExtraKeys): IN PROGRESS** (PR `feat/k1-extrakeys-in-app`; details in `FORK_DELTA_ANALYSIS.md`)
- **K1**: `loadIIABDefaultKeys()` moved out of upstream `ExtraKeysView` into app `IIABExtraKeys` (public APIs only). DONE (app side).
- **K3**: layout is now a single-source-of-truth constant. DONE.
- **K4**: falls back to a minimal layout if the default fails to load. DONE.
- **K5**: unit test validating the layout grid (`IIABExtraKeysTest`). DONE.
- Remaining: point the submodule to `appdevforall/termux-app` at clean upstream and commit the pointer.

**Phases 1–4: NOT STARTED.** Next: Phase 1 security — **D2**, **D6**, **S1**, **S3**, **M4**, **D12**.

## 1. Executive summary

The Controller is functional and shows real security intent (it SHA256-audits native binaries at build time, scrubs the keystore in CI, and scopes most broadcasts). But it carries debt on four fronts that scale badly toward the README's "millions of users" goal:
Expand Down Expand Up @@ -96,4 +115,4 @@ Begin field work immediately with this batch — all low-effort, high-signal, an
4. **First tests:** unit-test the pure functions listed in Phase 0 to seed the safety net (`M10`).
5. **Config extraction (start):** move scattered URLs/ports/versions into one constants class (`D3`, `S7`) — mechanical, unblocks later phases.

After this batch lands, open the Phase 1 security epic with `D2`, `D6`, and `S1` as the first three tickets.
After this
Loading