-
Notifications
You must be signed in to change notification settings - Fork 1
Feature/merge remove binary target #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ivolz
wants to merge
75
commits into
main
Choose a base branch
from
feature/merge-remove-binary-target
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 18 commits
Commits
Show all changes
75 commits
Select commit
Hold shift + click to select a range
21a4c22
Port mutators and message signing to Volley for 3.5.4
9ec1cfe
Align Volley initialization behavior with other service layers
2618d3f
Add empty service layer iniitialization option to match requirements …
a86484d
chore: integrate mini-sdk testing and update github workflows
b3549c5
fix: move core testing repo checkout into workspace to prevent github…
e8a7562
fix: migrate to okhttp sibling checkout pattern with PAT
cacbbf4
Add github workflow for build and test
bdaf78f
chore: align documentation and interface with okhttp for empty config
6af621e
ci: bump actions to support Node 24
1c8d639
fix(mutator): decouple mutator logic from legacy network fail variable
8266cb0
docs: update changelog for mutator decoupling
5b58e0d
docs: mark setProceedOnNetworkFail as obsolete
f2eea0c
test: remove obsolete reflection call targeting decoupled field
6c5c5d6
build: conditionally include test framework paths
6790e33
fix(sfv): return new item instance with params to prevent parameter d…
756e31b
fix(volley): getBaseHttpStack returns null when Approov is disabled t…
8354815
fix(sig): correct loop comparison in containsComponentIdentifier
2b4ed4b
fix(volley): make createConnection safe for HTTP and bypass pinning i…
4d7996f
fix(log): correct typo in already initialized warning message
49ea9f3
docs(volley): clarify mutator fallback behavior in javadoc
f8e2ac8
fix(volley): remove REJECTED from fallback header allowlist to preven…
b2d020f
Fix ehaviour on header substitution and adapt tests; complete testing…
0f6fe1b
Fix Copilot review comments and normalize token headers
be840ac
Make test dependencies conditional on project availability
6d77f81
Preserve ApproovException contract by trapping native fetch crashes
209a428
feat: implement thread-safe failure mode caching
005a33a
Update settings.graddle to support local and ci repo usage for mini-sdk
ae9dc48
Update ApproovTestSupport to use the latest cached failure field name…
09968f5
Fix FileInputStream leak in settings.gradle
ceb8e37
Shade BouncyCastle dependency and remove it from pom.xml
a50cda7
Docs: Update CHANGELOG.md with epic #519 changes
2ef0f81
Fix API initialization gating
44704de
Align default initialization comment parameter to null to avoid nativ…
9221d0b
fix: resolve ASN1Sequence class cast bug in signature decoding
f013839
Document initialize comment options and reinitialization in REFERENCE.md
6807fb9
Simplify initialization: delegate re-init decisions to platform SDK
5093d1a
fix: preserve service layer state on SDK initialization failure
a516d0d
Revise security policy for version support and reporting
naynovi d34678b
Merge branch 'pr-12' into feature/3.6.0
charlesoj6205 e326226
Relocate BouncyCastle to io.approov.internal.volley.bouncycastle
8cbf347
Remove hardcoded worker URL fallbacks from CI workflow
46d1149
fix: ignore empty config reinitialization when already initialized wi…
ba877c8
refactor: simplify empty config reinitialization check using isApproo…
9b88c3e
Align Volley empty config tests
charlesoj6205 df68b16
Merge feature/3.6.0 and update changelog
charlesoj6205 fb1525e
Fix consumer ProGuard keep rule for relocated BouncyCastle package
adriantuk 2bff4ab
Scope publish artifact upload to the service repository checkout
adriantuk 9f1b499
Allow tests to compile and run without the core testing framework
adriantuk b4e805d
Fix loss of leading fractional zeros in DecimalItem serialization
adriantuk 289a32f
Add migration notes for behavioral changes to USAGE.md
adriantuk 67f5d65
Document deliberate RFC 9421 deviations in the component provider
adriantuk d49e647
Remove overly broad consumer keep rule for (String, int) constructors
adriantuk 5ee43a2
Add contract test for PinningHostnameVerifier pin checking
adriantuk 3ea6050
Remove hardcoded worker endpoints from tests and gate live requests
adriantuk 3cb284d
Make the Base64 test stub behaviorally faithful and document the HTTP…
adriantuk de66d64
Document the intentional failure asymmetry between signing algorithms
adriantuk 4ca5c9a
Avoid duplicate CI runs for branches with open pull requests
adriantuk d1b5279
Drop Map overrides requiring Android API 24 from Parameters
adriantuk 5fa1b33
Remove editor settings from version control
adriantuk 69ce306
Drop redundant compileOnly declaration of the shadow jar
adriantuk 098259d
Remove leftover toString call on a String parameter
adriantuk 8a843aa
Record headers added by message signing in the request mutations
adriantuk c5fca9d
Document provenance and modifications of the vendored sfv package
adriantuk cc618bd
Rename initialization test to match the verified contract
adriantuk 790d061
Record review fixes in the changelog
adriantuk f26bf2a
Tolerate mini-sdk revisions without the testing reply URL accessors
adriantuk acebc4e
fix: guard secure string substitution against null/empty values
5cb4e5a
ci: bake service-layer version into AAR and validate CHANGELOG on pub…
d673143
fix: update contract test assertions for versioned setUserProperty
f7ec5ec
docs: complete version 3.5.5 documentation and changelog updates
ivolz b9ca778
Fix reviewer feedback and resolve inline thread comments on PR 9
ivolz 542e663
Address Copilot PR review comments regarding SECURITY.md grammar and …
ivolz b243ece
fix(message-signing): account-signing silent fallback symmetry and ty…
ivolz 37caa5a
Implement message signing fail-open policy for decoding and formattin…
ivolz 915511e
Fix GitHub Actions secrets syntax error in step level if checks
ivolz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,292 @@ | ||
| name: Build and Test | ||
|
|
||
| on: | ||
| push: | ||
| pull_request: | ||
|
|
||
| jobs: | ||
| build-and-test: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 45 | ||
| env: | ||
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | ||
| WORKSPACE: "${{ github.workspace }}" | ||
| GIT_BRANCH: "${{ github.ref }}" | ||
| CURRENT_TAG: "${{ github.ref_name }}" | ||
| # Worker endpoints: consumed from GitHub organisation variables first. | ||
| # If the org variable is not set the value is an empty string; the probe | ||
| # step below falls back to the same hardcoded defaults that are baked into | ||
| # the mini-sdk (MiniAttesterConfig / Approov.m), keeping them in sync. | ||
| # Worker management (create / redeploy) logic is centralized in the | ||
| # core-service-layers-testing script, but invoked here when needed. | ||
| TESTING_REPLY_URL: ${{ vars.TESTING_REPLY_URL }} | ||
| TESTING_REPLY_URL_UNPROTECTED: ${{ vars.TESTING_REPLY_URL_UNPROTECTED }} | ||
| # Required for the redeploy script invocation on failure | ||
| CLOUDFLARE_API_TOKEN_WORKERS_DEV: ${{ secrets.CLOUDFLARE_API_TOKEN_WORKERS_DEV }} | ||
| CLOUDFLARE_ACCOUNT_ID_WORKERS_DEV: ${{ secrets.CLOUDFLARE_ACCOUNT_ID_WORKERS_DEV }} | ||
|
|
||
| steps: | ||
| # ----------------------------------------------------------------------- | ||
| # 1. Checkout this repository | ||
| # ----------------------------------------------------------------------- | ||
| - name: Set up Git | ||
| run: git config --global --add safe.directory '*' | ||
|
|
||
| - name: Checkout approov-service-volley | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| path: approov-service-volley | ||
|
|
||
| # ----------------------------------------------------------------------- | ||
| # 2. Clone core-service-layers-testing as a sibling directory | ||
| # settings.gradle expects: ../core-service-layers-testing/... | ||
| # so both repos must sit under the same parent ($GITHUB_WORKSPACE). | ||
| # ----------------------------------------------------------------------- | ||
| - name: Checkout core-service-layers-testing | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| repository: approov/core-service-layers-testing | ||
| token: ${{ secrets.CORE_SERVICE_LAYERS_TESTING_PAT }} | ||
| path: core-service-layers-testing | ||
|
|
||
| # ----------------------------------------------------------------------- | ||
| # 3. Verify worker endpoints (with auto-redeploy) | ||
| # | ||
| # URLs are resolved with the following precedence (mirrors the mini-sdk | ||
| # fallback logic in MiniAttesterConfig / Approov.m): | ||
| # 1. GitHub org variable (TESTING_REPLY_URL / _UNPROTECTED) | ||
| # 2. Mini-SDK hardcoded defaults (replay.ivol.workers.dev / ...) | ||
| # | ||
| # If the workers are unavailable, this step invokes the management | ||
| # script in core-service-layers-testing to redeploy them. | ||
| # ----------------------------------------------------------------------- | ||
| - name: Verify worker endpoints | ||
| run: | | ||
| # ── URL resolution ────────────────────────────────────────────────── | ||
| PROTECTED_URL="${TESTING_REPLY_URL:-https://replay.ivol.workers.dev}" | ||
| UNPROTECTED_URL="${TESTING_REPLY_URL_UNPROTECTED:-https://replay-unprotected.ivol.workers.dev}" | ||
|
|
||
| echo "TESTING_REPLY_URL=$PROTECTED_URL" >> "$GITHUB_ENV" | ||
| echo "TESTING_REPLY_URL_UNPROTECTED=$UNPROTECTED_URL" >> "$GITHUB_ENV" | ||
|
|
||
| # ── Probe function ────────────────────────────────────────────────── | ||
| probe_worker() { | ||
| local url="$1" | ||
| curl --silent --show-error --fail --max-time 10 \ | ||
| -X POST "$url" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"check":"probe"}' | grep -q '"body"' | ||
| } | ||
|
|
||
| echo "==> Probing workers..." | ||
| if probe_worker "$PROTECTED_URL" && probe_worker "$UNPROTECTED_URL"; then | ||
| echo " All workers are healthy." | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo " WARNING: One or more workers are down. Attempting redeploy..." | ||
|
|
||
| # ── Invoke redeploy script ────────────────────────────────────────── | ||
| # The script is in the sibling directory cloned in Step 2. | ||
| # It uses the CLOUDFLARE_* env variables defined at the job level. | ||
| ./core-service-layers-testing/cloudflare-workers/redeploy-workers.sh | ||
|
|
||
| echo "==> Verifying after redeploy..." | ||
| # Try up to 3 times with a 5s delay between attempts | ||
| for i in {1..3}; do | ||
| if probe_worker "$PROTECTED_URL" && probe_worker "$UNPROTECTED_URL"; then | ||
| echo " Workers successfully restored." | ||
| exit 0 | ||
| fi | ||
| echo " Waiting for propagation (attempt $i/3)..." | ||
| sleep 5 | ||
| done | ||
|
|
||
| echo "ERROR: Workers are still unreachable after redeployment effort." | ||
| exit 1 | ||
|
|
||
| # ----------------------------------------------------------------------- | ||
| # 4. Java / Android toolchain setup | ||
| # ----------------------------------------------------------------------- | ||
| - name: Set Up Java | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| distribution: 'temurin' | ||
| java-version: '21' | ||
|
|
||
| - name: Install Android SDK command-line tools | ||
| run: | | ||
| sudo apt-get update -q | ||
| sudo apt-get install -y -q unzip curl | ||
| mkdir -p "$ANDROID_HOME/cmdline-tools" | ||
| curl -o android-sdk.zip \ | ||
| https://dl.google.com/android/repository/commandlinetools-linux-9123335_latest.zip | ||
| unzip -q android-sdk.zip -d "$ANDROID_HOME/cmdline-tools" | ||
| mv "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/tools" | ||
| rm android-sdk.zip | ||
| echo "ANDROID_HOME=$ANDROID_HOME" >> "$GITHUB_ENV" | ||
| echo "$ANDROID_HOME/cmdline-tools/tools/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator" >> "$GITHUB_PATH" | ||
|
|
||
| - name: Accept Android SDK licenses | ||
| run: yes | sdkmanager --licenses || true | ||
|
|
||
| - name: Install required Android SDK packages | ||
| run: | | ||
| sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0" | ||
|
|
||
| # ----------------------------------------------------------------------- | ||
| # 5. Build and run tests | ||
| # Gradle is invoked from inside the checked-out service directory. | ||
| # The mini-sdk is already available via the sibling path wired into | ||
| # settings.gradle — no extra configuration needed here. | ||
| # ----------------------------------------------------------------------- | ||
| - name: Build AAR | ||
| working-directory: approov-service-volley | ||
| run: ./gradlew assembleRelease | ||
|
|
||
| - name: Run unit tests | ||
| working-directory: approov-service-volley | ||
| env: | ||
| TESTING_REPLY_URL: ${{ env.TESTING_REPLY_URL }} | ||
| TESTING_REPLY_URL_UNPROTECTED: ${{ env.TESTING_REPLY_URL_UNPROTECTED }} | ||
| run: ./gradlew test | ||
|
|
||
| # ----------------------------------------------------------------------- | ||
| # 6. Print test summary to the console and to the Actions Job Summary | ||
| # Parses every JUnit XML produced by Gradle and emits: | ||
| # • a formatted table in the step log | ||
| # • a markdown table in the Job Summary (Actions UI → Summary tab) | ||
| # ----------------------------------------------------------------------- | ||
| - name: Print test summary | ||
| if: always() | ||
| working-directory: approov-service-volley | ||
| run: | | ||
| python3 - <<'EOF' | ||
| import os, sys, glob, xml.etree.ElementTree as ET | ||
| from collections import defaultdict | ||
|
|
||
| PASS = "\u2705" | ||
| FAIL = "\u274c" | ||
| SKIP = "\u23ed\ufe0f" | ||
| ERROR = "\u26a0\ufe0f" | ||
|
|
||
| results_root = "approov-service/build/test-results" | ||
| xml_files = sorted(glob.glob(f"{results_root}/**/*.xml", recursive=True)) | ||
|
|
||
| if not xml_files: | ||
| print("No test-result XML files found.") | ||
| sys.exit(0) | ||
|
|
||
| # Group suites by variant directory name (testDebugUnitTest, etc.) | ||
| by_variant = defaultdict(list) | ||
| for path in xml_files: | ||
| variant = os.path.basename(os.path.dirname(path)) | ||
| try: | ||
| root = ET.parse(path).getroot() | ||
| except ET.ParseError: | ||
| continue | ||
| suite = { | ||
| "name": root.get("name", os.path.basename(path)), | ||
| "tests": int(root.get("tests", 0)), | ||
| "failures": int(root.get("failures", 0)), | ||
| "errors": int(root.get("errors", 0)), | ||
| "skipped": int(root.get("skipped", 0)), | ||
| "time": float(root.get("time", 0)), | ||
| "cases": [], | ||
| } | ||
| for tc in root.findall("testcase"): | ||
| status = PASS | ||
| detail = "" | ||
| if tc.find("failure") is not None: | ||
| status = FAIL | ||
| detail = (tc.find("failure").get("message") or "").split("\n")[0][:120] | ||
| elif tc.find("error") is not None: | ||
| status = ERROR | ||
| detail = (tc.find("error").get("message") or "").split("\n")[0][:120] | ||
| elif tc.find("skipped") is not None: | ||
| status = SKIP | ||
| suite["cases"].append({ | ||
| "name": tc.get("name", "?"), | ||
| "time": float(tc.get("time", 0)), | ||
| "status": status, | ||
| "detail": detail, | ||
| }) | ||
| by_variant[variant].append(suite) | ||
|
|
||
| # ── Console output ────────────────────────────────────────────────── | ||
| overall_ok = True | ||
| for variant, suites in sorted(by_variant.items()): | ||
| total_t = sum(s["tests"] for s in suites) | ||
| total_f = sum(s["failures"] + s["errors"] for s in suites) | ||
| total_s = sum(s["skipped"] for s in suites) | ||
| total_p = total_t - total_f - total_s | ||
| icon = PASS if total_f == 0 else FAIL | ||
| if total_f > 0: | ||
| overall_ok = False | ||
| print() | ||
| print(f"{'='*70}") | ||
| print(f" {icon} {variant} | {total_p}/{total_t} passed " | ||
| f"| {total_f} failed | {total_s} skipped") | ||
| print(f"{'='*70}") | ||
| for suite in suites: | ||
| short = suite["name"].split(".")[-1] | ||
| p = suite["tests"] - suite["failures"] - suite["errors"] - suite["skipped"] | ||
| f = suite["failures"] + suite["errors"] | ||
| print(f" {PASS if f==0 else FAIL} {short:<55} {p}/{suite['tests']} ({suite['time']:.2f}s)") | ||
| for case in suite["cases"]: | ||
| if case["status"] != PASS: | ||
| print(f" {case['status']} {case['name']}") | ||
| if case["detail"]: | ||
| print(f" {case['detail']}") | ||
| print() | ||
|
|
||
| # ── GitHub Job Summary (markdown) ─────────────────────────────────── | ||
| summary_path = os.environ.get("GITHUB_STEP_SUMMARY", "") | ||
| if not summary_path: | ||
| sys.exit(0 if overall_ok else 1) | ||
|
|
||
| with open(summary_path, "a") as md: | ||
| md.write("## \U0001f9ea Unit Test Results\n\n") | ||
| for variant, suites in sorted(by_variant.items()): | ||
| total_t = sum(s["tests"] for s in suites) | ||
| total_f = sum(s["failures"] + s["errors"] for s in suites) | ||
| total_s = sum(s["skipped"] for s in suites) | ||
| total_p = total_t - total_f - total_s | ||
| badge = "\U0001f7e2 PASSED" if total_f == 0 else "\U0001f534 FAILED" | ||
| md.write(f"### {variant} {badge}\n\n") | ||
| md.write(f"> **{total_p} passed** | " | ||
| f"**{total_f} failed** | " | ||
| f"**{total_s} skipped** | " | ||
| f"**{total_t} total**\n\n") | ||
| md.write("| Status | Test suite | Tests | Failed | Skipped | Time |\n") | ||
| md.write("|--------|------------|------:|-------:|--------:|-----:|\n") | ||
| for suite in suites: | ||
| short = suite["name"].split(".")[-1] | ||
| f = suite["failures"] + suite["errors"] | ||
| icon = "\U0001f7e2" if f == 0 else "\U0001f534" | ||
| md.write(f"| {icon} | `{short}` | {suite['tests']} | {f} | {suite['skipped']} | {suite['time']:.2f}s |\n") | ||
| # Expand failures inline | ||
| failures = [c for s in suites for c in s["cases"] if c["status"] in (FAIL, ERROR)] | ||
| if failures: | ||
| md.write("\n<details><summary>Failed tests</summary>\n\n") | ||
| for c in failures: | ||
| md.write(f"- {c['status']} `{c['name']}`") | ||
| if c["detail"]: | ||
| md.write(f" \n > {c['detail']}") | ||
| md.write("\n") | ||
| md.write("\n</details>\n") | ||
| md.write("\n") | ||
|
|
||
| sys.exit(0 if overall_ok else 1) | ||
| EOF | ||
|
|
||
| # ----------------------------------------------------------------------- | ||
| # 7. Upload HTML reports as a downloadable artifact | ||
| # ----------------------------------------------------------------------- | ||
| - name: Upload test results | ||
| if: always() | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: test-results-${{ github.run_number }} | ||
| path: approov-service-volley/approov-service/build/reports/tests/ | ||
| retention-days: 14 | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.