Skip to content
Open
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
57 changes: 57 additions & 0 deletions .github/scripts/tests/test_track_build_size.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""Tests for track_build_size.py regression handling.

Run directly:
python3 -m unittest discover -s .github/scripts/tests -p "test_*.py" -v
"""
from __future__ import annotations

import contextlib
import importlib.util
import io
import os
import pathlib
import tempfile
import unittest

SCRIPT = pathlib.Path(__file__).resolve().parents[1] / "track_build_size.py"
spec = importlib.util.spec_from_file_location("track_build_size", SCRIPT)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)

APK = "android/app/build/outputs/apk/release/app-release.apk"


class AndroidRegressionTest(unittest.TestCase):
def setUp(self):
self._old_cwd = os.getcwd()
self._tmp = tempfile.TemporaryDirectory()
os.chdir(self._tmp.name)
pathlib.Path(APK).parent.mkdir(parents=True)

def tearDown(self):
os.chdir(self._old_cwd)
self._tmp.cleanup()

def _write_apk(self, size_mb: float):
pathlib.Path(APK).write_bytes(b"x" * int(size_mb * 1024 * 1024))

def test_growth_over_five_percent_warns(self):
self._write_apk(10.6)
out = io.StringIO()
with contextlib.redirect_stdout(out):
result = module.track_android_size(10.0)
self.assertEqual(result, "warning")
self.assertIn("::warning::Android APK size increased", out.getvalue())

def test_growth_within_five_percent_does_not_warn(self):
self._write_apk(10.2)
out = io.StringIO()
with contextlib.redirect_stdout(out):
result = module.track_android_size(10.0)
self.assertNotEqual(result, "warning")
self.assertNotIn("::warning::", out.getvalue())


if __name__ == "__main__":
unittest.main()
9 changes: 8 additions & 1 deletion .github/scripts/track_build_size.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,19 @@ def main():

platform = sys.argv[1].lower()
base_size_mb = None
if len(sys.argv) > 2:
if len(sys.argv) > 2 and sys.argv[2].strip():
try:
base_size_mb = float(sys.argv[2])
except ValueError:
pass

if base_size_mb is None and os.environ.get("GITHUB_REF") == "refs/heads/main":
print(
f"::error::No {platform} size baseline on main. "
f"Set the {platform.upper()}_BASE_SIZE_MB repository variable so the 5% check can run."
)
sys.exit(1)

if platform == "android":
result = track_android_size(base_size_mb)
elif platform == "ios":
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/android-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ jobs:

- name: Measure APK size
run: |
python3 ../.github/scripts/track_build_size.py android
python3 ../.github/scripts/track_build_size.py android "${{ vars.ANDROID_BASE_SIZE_MB }}"

# task #173: A release build must never ship placeholder certificate pins — the
# failure mode is silent until every user hits a connection failure in production.
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/android-dependency-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
# scanning happening without blocking unrelated PRs.
dependency-check:
runs-on: ubuntu-latest
# Caps the run so a stalled NVD sync cannot hang the job for hours (see #178).
timeout-minutes: 45
# The "Alert on failure" step files a GitHub issue on scheduled-run
# failures, which needs issues:write — the default GITHUB_TOKEN is
# read-only, so without this the alert itself fails with a 403.
Expand Down Expand Up @@ -82,6 +84,9 @@ jobs:
# failure — anything else (a real CVSS >= 7.0 finding, or any other error)
# still fails the job.
- name: Scan dependencies for high severity vulnerabilities
env:
# Optional: with a key the NVD feed is not rate-limited (HTTP 429).
NVD_API_KEY: ${{ secrets.NVD_API_KEY }}
run: |
set +e
./gradlew dependencyCheckAggregate 2>&1 | tee dependency-check-output.log
Expand All @@ -99,6 +104,17 @@ jobs:

exit "$STATUS"

# Keeps the scan output as a run artifact, so the cause of a failed scheduled run
# can be read without opening the log. Refs #557, #558.
- name: Keep dependency-check output
if: always()
uses: actions/upload-artifact@v4
with:
name: dependency-check-output
path: android/dependency-check-output.log
if-no-files-found: ignore
retention-days: 30

- name: Alert on failure (scheduled run)
if: failure() && github.event_name == 'schedule'
uses: actions/github-script@v7
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ios-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ jobs:

- name: Measure app size
run: |
python3 "$GITHUB_WORKSPACE/.github/scripts/track_build_size.py" ios
python3 "$GITHUB_WORKSPACE/.github/scripts/track_build_size.py" ios "${{ vars.IOS_BASE_SIZE_MB }}"

# Runs hosted tests that require a real app process (Keychain, UNUserNotificationCenter).
# These tests are in EthosProtocolTests target within the Xcode project, not in the SPM
Expand Down
Loading