Skip to content

Commit 1e1c694

Browse files
committed
Release v1.8.177 — SHA-pin every third-party Action + osv-scanner binary
Supply-chain hardening. 7 of 8 workflows previously used floating major-tag pins (actions/checkout@v4, gradle/actions/setup-gradle@v4, reactivecircus/android-emulator-runner@v2, google/osv-scanner-action@v2.0.2, etc). A compromise of any action's repository would re-point those tags at malicious code, executed by the next CI run. release.yml additionally curl-downloaded the osv-scanner v2.0.2 binary without SHA-256 verification — a CDN-level swap would run unverified code on the runner. Changes: SHA-pinned 9 distinct action@tag references across all 8 workflows. SHAs resolved via `gh api repos/<owner>/<repo>/git/refs/tags/<tag>` against the live GitHub API on the run date; annotated tags dereferenced one level. actions/checkout@v4 -> @34e114876b0b... actions/setup-java@v4 -> @c1e323688fd8... actions/upload-artifact@v4 -> @ea165f8d65b6... actions/dependency-review-action@v4 -> @4901385134134... gradle/actions/wrapper-validation@v4 -> @48b5f213c810... gradle/actions/setup-gradle@v4 -> @48b5f213c810... lukka/get-cmake@v4.0.2 -> @ea004816823209... google/osv-scanner-action@v2.0.2 -> @e69cc6c86b31... reactivecircus/android-emulator-runner@v2 -> @e89f39f1abbb... SHA-256-pinned the osv-scanner v2.0.2 binary in release.yml. New OSV_BINARY_SHA256 env carries 3abcfd7126c453a00421487e721b296e0cb68085bd431d6cef60872774170fc8; the step runs sha256sum against the downloaded binary and refuses to execute on mismatch with a clear ::error:: message. A future v2.x.y bump requires re-recording the digest alongside the URL bump. Closes RESEARCH_FEATURE_PLAN.md F19 + F20. Verification: - grep -rn "uses: [a-zA-Z0-9_/.-]\+@v" .github/workflows/ -> no matches - bash scripts/check-fastlane-metadata.sh -> OK (versionCode 1977) - bash scripts/check-repo-hygiene.sh -> OK - osv-scanner SHA-256 confirmed off-runner via curl + sha256sum - Gradle gates deferred to maintainer host per CLAUDE.md
1 parent df35986 commit 1e1c694

12 files changed

Lines changed: 120 additions & 45 deletions

File tree

.github/workflows/android.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ jobs:
3838
runs-on: ubuntu-latest
3939

4040
steps:
41-
- uses: actions/checkout@v4
41+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
4242
with:
4343
submodules: recursive
4444

45-
- uses: gradle/actions/wrapper-validation@v4
45+
- uses: gradle/actions/wrapper-validation@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
4646

4747
- name: Check root crash/replay logs
4848
run: bash scripts/check-no-root-crash-logs.sh
@@ -60,16 +60,16 @@ jobs:
6060
run: bash scripts/check-fastlane-metadata.sh
6161

6262
- name: Set up JDK 17
63-
uses: actions/setup-java@v4
63+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
6464
with:
6565
java-version: 17
6666
distribution: temurin
6767

6868
- name: Set up CMake and Ninja
69-
uses: lukka/get-cmake@v4.0.2
69+
uses: lukka/get-cmake@ea004816823209b8d1211e47b216185caee12cc5 # v4.0.2
7070

7171
- name: Cache Gradle
72-
uses: gradle/actions/setup-gradle@v4
72+
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
7373

7474
- name: Verify no-network contract (N7.1)
7575
run: ./gradlew :app:verifyNoInternetPermission
@@ -123,14 +123,14 @@ jobs:
123123
echo "All shipped native libraries (if any) are 16 KB aligned."
124124
125125
- name: Upload debug APK
126-
uses: actions/upload-artifact@v4
126+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
127127
with:
128128
name: app-debug.apk
129129
path: app/build/outputs/apk/debug/app-debug.apk
130130

131131
- name: Upload lint report
132132
if: always()
133-
uses: actions/upload-artifact@v4
133+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
134134
with:
135135
name: lint-debug-report
136136
path: |
@@ -140,7 +140,7 @@ jobs:
140140
141141
- name: Upload unit-test report
142142
if: always()
143-
uses: actions/upload-artifact@v4
143+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
144144
with:
145145
name: unit-test-report
146146
path: app/build/reports/tests/testDebugUnitTest/

.github/workflows/crowdin-upload.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121

2222
steps:
2323
- name: Checkout
24-
uses: actions/checkout@v4
24+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2525
- name: Upload
2626
# SHA pin: crowdin/github-action@v2 = 8868a33591d21088edfc398968173a3b98d51706
2727
# Verified 2026-05-17 via `GET /repos/crowdin/github-action/git/refs/tags/v2`.

.github/workflows/dependency-scan.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,36 +40,36 @@ jobs:
4040
if: github.event_name == 'pull_request'
4141
runs-on: ubuntu-latest
4242
steps:
43-
- uses: actions/checkout@v4
43+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
4444
with:
4545
submodules: recursive
4646
- name: Run dependency-review
47-
uses: actions/dependency-review-action@v4
47+
uses: actions/dependency-review-action@4901385134134e04cec5fbe5ddfe3b2c5bd5d976 # v4
4848
with:
4949
fail-on-severity: high
5050
comment-summary-in-pr: on-failure
5151

5252
osv-scanner:
5353
runs-on: ubuntu-latest
5454
steps:
55-
- uses: actions/checkout@v4
55+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
5656
with:
5757
submodules: recursive
5858

5959
- name: Set up JDK 17
60-
uses: actions/setup-java@v4
60+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
6161
with:
6262
java-version: 17
6363
distribution: temurin
6464

6565
- name: Cache Gradle
66-
uses: gradle/actions/setup-gradle@v4
66+
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
6767

6868
- name: Generate Gradle dependency tree
6969
run: ./gradlew :app:dependencies --configuration releaseRuntimeClasspath > gradle-deps.txt
7070

7171
- name: Run OSV-Scanner against the lockfiles + dep tree
72-
uses: google/osv-scanner-action/osv-scanner-action@v2.0.2
72+
uses: google/osv-scanner-action/osv-scanner-action@e69cc6c86b31f1e7e23935bbe7031b50e51082de # v2.0.2
7373
with:
7474
scan-args: |-
7575
--recursive
@@ -79,7 +79,7 @@ jobs:
7979

8080
- name: Upload dep tree artifact
8181
if: always()
82-
uses: actions/upload-artifact@v4
82+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
8383
with:
8484
name: gradle-dep-tree
8585
path: gradle-deps.txt

.github/workflows/emulator-smoke.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,23 @@ jobs:
2828
timeout-minutes: 35
2929

3030
steps:
31-
- uses: actions/checkout@v4
31+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3232
with:
3333
submodules: recursive
3434

35-
- uses: gradle/actions/wrapper-validation@v4
35+
- uses: gradle/actions/wrapper-validation@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
3636

3737
- name: Set up JDK 17
38-
uses: actions/setup-java@v4
38+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
3939
with:
4040
java-version: 17
4141
distribution: temurin
4242

4343
- name: Set up CMake and Ninja
44-
uses: lukka/get-cmake@v4.0.2
44+
uses: lukka/get-cmake@ea004816823209b8d1211e47b216185caee12cc5 # v4.0.2
4545

4646
- name: Cache Gradle
47-
uses: gradle/actions/setup-gradle@v4
47+
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
4848

4949
- name: Build debug APK
5050
run: ./gradlew :app:assembleDebug
@@ -56,7 +56,7 @@ jobs:
5656
sudo udevadm trigger --name-match=kvm
5757
5858
- name: Launch settings on emulator
59-
uses: reactivecircus/android-emulator-runner@v2
59+
uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2
6060
with:
6161
api-level: 35
6262
arch: x86_64
@@ -77,7 +77,7 @@ jobs:
7777
7878
- name: Upload emulator smoke logcat
7979
if: always()
80-
uses: actions/upload-artifact@v4
80+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
8181
with:
8282
name: emulator-smoke-logcat
8383
path: emulator-smoke-logcat.txt

.github/workflows/release.yml

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@ jobs:
3838
env:
3939
SIGNING_KEYSTORE_BASE64: ${{ secrets.SIGNING_KEYSTORE_BASE64 }}
4040
steps:
41-
- uses: actions/checkout@v4
41+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
4242
with:
4343
submodules: recursive
4444
fetch-depth: 0
4545

46-
- uses: gradle/actions/wrapper-validation@v4
46+
- uses: gradle/actions/wrapper-validation@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
4747

4848
- name: Set up JDK 17
49-
uses: actions/setup-java@v4
49+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
5050
with:
5151
java-version: 17
5252
distribution: temurin
5353

5454
- name: Cache Gradle
55-
uses: gradle/actions/setup-gradle@v4
55+
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
5656

5757
- name: Make gradlew executable
5858
run: chmod +x ./gradlew
@@ -90,9 +90,23 @@ jobs:
9090
- name: Run OSV-Scanner against the release tree
9191
id: osv-scan
9292
continue-on-error: true
93+
env:
94+
# SHA-256 of google/osv-scanner v2.0.2 linux_amd64. Pin the binary
95+
# by content hash so a compromised GitHub Releases CDN cannot swap a
96+
# malicious build under the same version tag. Refresh this value
97+
# alongside any v2.0.2 -> v2.x.y bump and re-record the digest.
98+
OSV_BINARY_SHA256: "3abcfd7126c453a00421487e721b296e0cb68085bd431d6cef60872774170fc8"
9399
run: |
94100
set +e
95101
curl -sSL -o osv-scanner "https://github.com/google/osv-scanner/releases/download/v2.0.2/osv-scanner_linux_amd64"
102+
actual_sha="$(sha256sum osv-scanner | awk '{print $1}')"
103+
if [ "$actual_sha" != "$OSV_BINARY_SHA256" ]; then
104+
echo "::error::osv-scanner SHA-256 mismatch."
105+
echo " expected: $OSV_BINARY_SHA256"
106+
echo " actual: $actual_sha"
107+
echo " Refusing to execute an unverified binary."
108+
exit 1
109+
fi
96110
chmod +x osv-scanner
97111
./osv-scanner --recursive --skip-git --format=json ./ > osv-result.json
98112
osv_exit=$?
@@ -127,7 +141,7 @@ jobs:
127141
128142
- name: Upload OSV scan artifacts
129143
if: always()
130-
uses: actions/upload-artifact@v4
144+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
131145
with:
132146
name: swiftfloris-v${{ inputs.version }}-osv
133147
path: |
@@ -208,7 +222,7 @@ jobs:
208222
echo '```' >> "$GITHUB_STEP_SUMMARY"
209223
210224
- name: Upload artifacts
211-
uses: actions/upload-artifact@v4
225+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
212226
with:
213227
name: swiftfloris-v${{ inputs.version }}
214228
path: |

.github/workflows/reproducible-build.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,31 +48,31 @@ jobs:
4848
runs-on: ubuntu-latest
4949

5050
steps:
51-
- uses: actions/checkout@v4
51+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
5252
with:
5353
submodules: recursive
5454
fetch-depth: 0
5555

56-
- uses: gradle/actions/wrapper-validation@v4
56+
- uses: gradle/actions/wrapper-validation@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
5757

5858
- name: Set up JDK 17
59-
uses: actions/setup-java@v4
59+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
6060
with:
6161
java-version: 17
6262
distribution: temurin
6363

6464
- name: Set up CMake and Ninja
65-
uses: lukka/get-cmake@v4.0.2
65+
uses: lukka/get-cmake@ea004816823209b8d1211e47b216185caee12cc5 # v4.0.2
6666

6767
- name: Cache Gradle
68-
uses: gradle/actions/setup-gradle@v4
68+
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
6969

7070
- name: Verify release APK reproducibility
7171
run: bash scripts/verify-reproducible-apk.sh "$RUNNER_TEMP/reproducible-apk"
7272

7373
- name: Upload reproducibility artifacts
7474
if: always()
75-
uses: actions/upload-artifact@v4
75+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
7676
with:
7777
name: reproducible-apk-${{ github.sha }}
7878
path: ${{ runner.temp }}/reproducible-apk/

.github/workflows/roborazzi-baseline.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,20 @@ jobs:
3636
runs-on: ubuntu-latest
3737

3838
steps:
39-
- uses: actions/checkout@v4
39+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
4040
with:
4141
submodules: recursive
4242

43-
- uses: gradle/actions/wrapper-validation@v4
43+
- uses: gradle/actions/wrapper-validation@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
4444

4545
- name: Set up JDK 17
46-
uses: actions/setup-java@v4
46+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
4747
with:
4848
java-version: 17
4949
distribution: temurin
5050

5151
- name: Cache Gradle
52-
uses: gradle/actions/setup-gradle@v4
52+
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4
5353

5454
- name: Make gradlew executable
5555
run: chmod +x ./gradlew
@@ -81,7 +81,7 @@ jobs:
8181
8282
- name: Upload baseline artifact
8383
if: always()
84-
uses: actions/upload-artifact@v4
84+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
8585
with:
8686
name: roborazzi-baselines-${{ github.run_id }}${{ inputs.message && format('-{0}', inputs.message) || '' }}
8787
path: app/src/test/snapshots/images/

CHANGELOG.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,62 @@
22

33
All SwiftFloris release history is consolidated here. This replaces the former root-level `RELEASE_NOTES_v*.md` file-per-release pattern.
44

5+
<a id="v1.8.177"></a>
6+
## v1.8.177
7+
8+
Released: 2026-05-25
9+
10+
### Supply-chain hardening (RESEARCH_FEATURE_PLAN.md F19 + F20)
11+
12+
The 2026-05-25 build/CI reconnaissance pass found that 7 of 8 GitHub Actions workflows used floating major-tag pins (e.g. `actions/checkout@v4`, `gradle/actions/setup-gradle@v4`, `reactivecircus/android-emulator-runner@v2`, `google/osv-scanner-action@v2.0.2`). A floating tag's underlying commit can be re-pointed by the action's owner after the fact; a compromise of any action's repo would re-point the tag at malicious code, and the next CI run on SwiftFloris would execute it. Only `crowdin-upload.yml` and `validate-strings-no-translations.yml` already SHA-pinned. Additionally, `release.yml`'s OSV-Scanner step downloaded the v2.0.2 binary via curl without SHA-256 verification — a CDN-level swap would similarly run unverified code on the runner.
13+
14+
### Changes
15+
16+
- **SHA-pinned every third-party action across all 8 workflows.** The mapping (each replacement is exact `action@tag` → `action@<sha> # tag`):
17+
- `actions/checkout@v4` → `@34e114876b0b11c390a56381ad16ebd13914f8d5`
18+
- `actions/setup-java@v4` → `@c1e323688fd81a25caa38c78aa6df2d33d3e20d9`
19+
- `actions/upload-artifact@v4` → `@ea165f8d65b6e75b540449e92b4886f43607fa02`
20+
- `actions/dependency-review-action@v4` → `@4901385134134e04cec5fbe5ddfe3b2c5bd5d976`
21+
- `gradle/actions/wrapper-validation@v4` → `@48b5f213c81028ace310571dc5ec0fbbca0b2947`
22+
- `gradle/actions/setup-gradle@v4` → `@48b5f213c81028ace310571dc5ec0fbbca0b2947`
23+
- `lukka/get-cmake@v4.0.2` → `@ea004816823209b8d1211e47b216185caee12cc5`
24+
- `google/osv-scanner-action/osv-scanner-action@v2.0.2` → `@e69cc6c86b31f1e7e23935bbe7031b50e51082de`
25+
- `reactivecircus/android-emulator-runner@v2` → `@e89f39f1abbbd05b1113a29cf4db69e7540cae5a`
26+
SHAs were resolved via `gh api repos/<owner>/<repo>/git/refs/tags/<tag>` against the live GitHub API on the run date; annotated tags were dereferenced one level to the underlying commit object.
27+
- **SHA-256-pinned the `osv-scanner` v2.0.2 binary in `.github/workflows/release.yml`.** Added an `OSV_BINARY_SHA256` env on the OSV scan step (value `3abcfd7126c453a00421487e721b296e0cb68085bd431d6cef60872774170fc8`); the step now runs `sha256sum` against the downloaded binary and refuses to execute on mismatch with a clear `::error::` message. A future bump to `v2.x.y` requires re-recording the digest alongside the URL bump.
28+
29+
### Verification
30+
31+
- `grep -rn "uses: [a-zA-Z0-9_/.-]\+@v" .github/workflows/` returns no matches (no unpinned actions remain at HEAD).
32+
- `grep -rn "uses: " .github/workflows/` returns 41 references, all carrying `@<sha> # <tag>` form.
33+
- `curl -sSL .../osv-scanner_linux_amd64 | sha256sum` was computed off-runner to confirm the env value: `3abcfd7126c453a00421487e721b296e0cb68085bd431d6cef60872774170fc8`.
34+
- `bash scripts/check-repo-hygiene.sh` → OK.
35+
- `bash scripts/check-fastlane-metadata.sh` → OK (versionCode 1977).
36+
37+
### Bump guidance
38+
39+
To bump an action across the project:
40+
1. Pick the new version tag.
41+
2. Resolve the commit SHA via `gh api repos/<owner>/<repo>/git/refs/tags/<tag>` (dereference annotated tags).
42+
3. Replace every occurrence of the old SHA with the new SHA; update the trailing `# vN.Y` comment to match.
43+
4. If the new tag changes major version, treat as a breaking change and run the workflow on a draft branch first.
44+
45+
### Files Touched
46+
47+
- `.github/workflows/android.yml`
48+
- `.github/workflows/dependency-scan.yml`
49+
- `.github/workflows/emulator-smoke.yml`
50+
- `.github/workflows/reproducible-build.yml`
51+
- `.github/workflows/release.yml` (SHA-pins + OSV binary verification)
52+
- `.github/workflows/roborazzi-baseline.yml`
53+
- `.github/workflows/crowdin-upload.yml`
54+
- `.github/workflows/validate-strings-no-translations.yml`
55+
- `fastlane/metadata/android/en-US/changelogs/1977.txt` (new)
56+
- `gradle.properties` (versionCode 1976→1977, versionName 1.8.176→1.8.177)
57+
- `README.md` (version badge)
58+
- `CHANGELOG.md` (this section)
59+
- `RESEARCH_FEATURE_PLAN.md` (tick F19 + F20)
60+
561
<a id="v1.8.176"></a>
662
## v1.8.176
763

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SwiftFloris
22

3-
![Version](https://img.shields.io/badge/version-v1.8.176-blue) ![License](https://img.shields.io/badge/license-Apache%202.0-green) ![Platform](https://img.shields.io/badge/platform-Android%208.0+-orange) ![Network](https://img.shields.io/badge/network-none-lightgrey) ![SwiftKey migration](https://img.shields.io/badge/SwiftKey%20migration-window%20closes%202026--05--31-red)
3+
![Version](https://img.shields.io/badge/version-v1.8.177-blue) ![License](https://img.shields.io/badge/license-Apache%202.0-green) ![Platform](https://img.shields.io/badge/platform-Android%208.0+-orange) ![Network](https://img.shields.io/badge/network-none-lightgrey) ![SwiftKey migration](https://img.shields.io/badge/SwiftKey%20migration-window%20closes%202026--05--31-red)
44

55
**SwiftFloris** is a privacy-first Android keyboard, forked from FlorisBoard and pushed toward SwiftKey-class multilingual typing without the cloud. It ships under Apache-2.0, holds no `INTERNET` permission, and binds zero accounts.
66

RESEARCH_FEATURE_PLAN.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -993,9 +993,9 @@ The items above promote to:
993993

994994
- [ ] **P1** — F18 — **F5 refactor**: ship a `Default SmartComposeProvider` that consumes the existing `PersonalTrigramStore` + `PersonalBigramStore` + `ColdStartNextWordPriors` chain (instead of returning `NoSuggestion`). The wire-up at `NlpManager.kt:290` already exists. This makes ghost-text work without an addon. Touches: new `ime/smartcompose/HeuristicSmartComposeProvider.kt`, `SmartComposeProviderRegistry`, `app/AppPrefs.kt` (gate), `app/settings/typing/`. Acceptance: with the new toggle on and confidence-gated, ghost text renders inline from the existing trigram chain. Replaces / refines F5. Complexity: S-M.
995995

996-
- [ ] **P1** — F19 — **SHA-pin every third-party action**. Touches: `android.yml`, `release.yml`, `dependency-scan.yml`, `emulator-smoke.yml`, `reproducible-build.yml`, `roborazzi-baseline.yml`. Acceptance: every `uses: foo/bar@vN` becomes `uses: foo/bar@<sha>` with a comment recording the version. Complexity: S.
996+
- [x] **P1** — F19 — **SHA-pin every third-party action**. Touches: every workflow under `.github/workflows/`. Acceptance: every `uses: foo/bar@vN` becomes `uses: foo/bar@<sha>` with a comment recording the version. Complexity: S. **Shipped v1.8.177 (2026-05-25)** — 9 distinct action references SHA-pinned across all 8 workflows; SHAs resolved via `gh api`; full mapping in `CHANGELOG.md#v1.8.177`.
997997

998-
- [ ] **P1** — F20 — **SHA-256-pin the `osv-scanner v2.0.2` curl download** in `release.yml:95` (or migrate to the SHA-pinned `google/osv-scanner-action`). Acceptance: planted swap of the URL fails CI. Complexity: S.
998+
- [x] **P1** — F20 — **SHA-256-pin the `osv-scanner v2.0.2` curl download** in `release.yml:95`. Acceptance: planted swap of the URL fails CI. Complexity: S. **Shipped v1.8.177 (2026-05-25)**`OSV_BINARY_SHA256` env carries `3abcfd7126c453a00421487e721b296e0cb68085bd431d6cef60872774170fc8`; binary refuses to execute on mismatch.
999999

10001000
- [ ] **P1** — F21 — **Train an Apache-2.0 glide model from the MIT-licensed FUTO swipe dataset**. The 1.04M-row dataset at `huggingface.co/datasets/futo-org/swipe.futo.org` is MIT. Training is off-device; model ships in `addons/swipe-model-swiftfloris/` or inside the existing `swiftfloris-statistical` engine as a quantized weights file. Acceptance: N1.4 replay benchmark shows accuracy improvement vs `StatisticalGlideTypingClassifier`. Complexity: XL (out-of-tree training + integration). Priority gated on someone with ML infra; can promote into ROADMAP §6 N1.1 alternative.
10011001

0 commit comments

Comments
 (0)