Skip to content

Remove checked-in test.keystore and generate it dynamically during tests - #10923

Merged
jonathanpeppers merged 6 commits into
mainfrom
copilot/remove-test-keystore-file
Mar 13, 2026
Merged

Remove checked-in test.keystore and generate it dynamically during tests#10923
jonathanpeppers merged 6 commits into
mainfrom
copilot/remove-test-keystore-file

Conversation

Copilot AI commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Binary test.keystore checked into the repo triggers credential scanning warnings requiring ongoing suppression maintenance. Replace with dynamic generation at test time.

Changes

  • Delete src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/test.keystore
  • ResourceData.csGetKeystore() now generates a keystore via keytool process, cached per test run with thread-safe locking. Added GenerateKeystore() public helper.
  • KeyToolTests.csGetValidKeyStore() uses AndroidCreateDebugKey task instead of extracting the embedded resource
  • TestApks.targetsDeployTestAabs generates keystore into $(IntermediateOutputPath) via Exec keytool, gated by !Exists condition. Platform-aware keytool path via $(HostOS).
  • .gdn/.gdnsuppress — Remove the now-unnecessary test.keystore suppression entry

Keystore generation

All generated keystores use the same parameters as the original:

keytool -genkeypair -v -keystore <path> -alias mykey -keyalg RSA -keysize 2048 \
  -validity 10000 -storepass android -keypass android \
  -dname "CN=Test, OU=Test, O=Test, L=Test, ST=Test, C=US"

Callers of ResourceData.GetKeystore() (e.g., InstallTests.cs) required no changes — the method signature is preserved, only the backing implementation changed from embedded resource to dynamic generation.

Original prompt

This section details on the original issue you should resolve

<issue_title>Remove checked-in test.keystore and generate it dynamically during tests</issue_title>
<issue_description>## Problem

The file src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/test.keystore is a binary keystore checked into the repository. This triggers credential scanning warnings because the keystore and its passwords (android / mykey) are committed to source control.

While this is a harmless test-only keystore, it creates ongoing compliance noise and suppression maintenance.

Proposed Solution

Delete test.keystore from the repo and generate it dynamically at test time using keytool:

keytool -genkeypair -v -keystore test.keystore -alias mykey -keyalg RSA -keysize 2048 -validity 10000 -storepass android -keypass android -dname "CN=Test, OU=Test, O=Test, L=Test, ST=Test, C=US"

Files that need updating:

  1. ResourceData.cs - GetKeystore() helper that loads test.keystore as an embedded resource. Change to generate a keystore on-the-fly or from a shared test fixture.
  2. KeyToolTests.cs - GetValidKeyStore() extracts the embedded keystore to a temp file. Change to generate it.
  3. InstallTests.cs - ChangeKeystoreRedeploy and TestAndroidStoreKey tests add test.keystore as a BuildItem with BinaryContent. Change to use a dynamically generated keystore.
  4. build-tools/scripts/TestApks.targets - DeployTestAabs target references the keystore by full path on disk. Change to generate before use.
  5. .gdn/.gdnsuppress - Remove the suppression entry for test.keystore since the file will no longer exist.
  6. Xamarin.ProjectTools.csproj - Remove the embedded resource entry for test.keystore.

Approach

A helper method (e.g., in ResourceData.cs or a new test utility) could generate a keystore once per test run into a temp directory, and all consumers reference it from there. This keeps the same test coverage while eliminating the checked-in credential.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits March 12, 2026 15:29
- Delete test.keystore binary from Resources/Base/
- Update ResourceData.GetKeystore() to generate keystore via keytool
- Add ResourceData.GenerateKeystore() shared helper
- Update KeyToolTests.GetValidKeyStore() to use AndroidCreateDebugKey task
- Update TestApks.targets to generate keystore via Exec before DeployTestAabs
- Remove test.keystore suppression from .gdn/.gdnsuppress

Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com>
Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com>
Copilot AI changed the title [WIP] Remove checked-in test.keystore and generate dynamically Remove checked-in test.keystore and generate it dynamically during tests Mar 12, 2026
…s directly

Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com>

@jonathanpeppers jonathanpeppers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI Review Summary

Verdict: ⚠️ Needs Changes

Found 1 issue across 5 changed files.

  • ⚠️ MSBuild targets: _KeytoolPath uses hardcoded backslash \ but the target is cross-platform (TestApks.targets:224)

CI Status

Linux build ✅ passed. Mac and Windows builds still in progress — review will need re-validation once CI completes.

What's Good

  • 👍 Thread-safe caching in ResourceData.GetKeystore() with proper lock + null check pattern
  • 👍 GenerateKeystore() exposed as a reusable public helper with sensible defaults
  • 👍 KeyToolTests.cs correctly uses the AndroidCreateDebugKey MSBuild task (the system under test) to generate its test keystore
  • 👍 !Exists guard on the <Exec> prevents redundant regeneration
  • 👍 Proper cleanup of temp keystore in finally block
  • 👍 Good error reporting with stderr capture in GenerateKeystore()
  • 👍 Signature change from GetKeystore(string)GetKeystore() is safe — all 3 callers in InstallTests.cs use the parameterless form
  • 👍 .csproj doesn't need updating — the wildcard Resources\**\* glob naturally stops matching the deleted file

Review generated by android-reviewer from review guidelines.

Comment thread build-tools/scripts/TestApks.targets
@jonathanpeppers
jonathanpeppers marked this pull request as ready for review March 12, 2026 18:01
Copilot AI review requested due to automatic review settings March 12, 2026 18:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the checked-in test.keystore binary (which triggers credential scanning) and replaces it with keystore generation at test time to eliminate ongoing suppression maintenance.

Changes:

  • Removed test.keystore from Xamarin.ProjectTools resources.
  • Updated ResourceData.GetKeystore() to generate and cache a keystore dynamically via keytool.
  • Updated test/build flows to generate keystores on demand (unit tests via AndroidCreateDebugKey, AAB deploy via MSBuild Exec), and removed the related .gdn suppression.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ResourceData.cs Replaces embedded keystore loading with on-the-fly keystore generation and caching.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/KeyToolTests.cs Generates a valid keystore for tests using AndroidCreateDebugKey instead of an embedded resource.
build-tools/scripts/TestApks.targets Generates test.keystore at build/test time for AAB deployment rather than relying on a repo file.
.gdn/.gdnsuppress Removes the suppression entry that was only needed for the checked-in keystore.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/test.keystore Deleted binary keystore from the repository.

Comment thread build-tools/scripts/TestApks.targets Outdated
Comment thread build-tools/scripts/TestApks.targets
Comment thread build-tools/scripts/TestApks.targets Outdated
The default keystore format varies by JDK version (JKS before JDK 9,
PKCS12 from JDK 9+). Explicitly specifying -storetype pkcs12 ensures
consistent behavior regardless of the JDK version used.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

Copy link
Copy Markdown
Member

@copilot there is one test failure:

ListInvalidPassword

Result Details
Failed Yesterday on 292d18e9c000005
Duration0:00:00.950
Ownernot available
Date started3/12/2026, 5:15:24 PM
Date completed3/12/2026, 5:15:25 PM
Failing sinceYesterday
Failing since build[11.0.0-preview.1.26162.1+azdo.13533805](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13533805)

Debug

Work items

Attachments

History

1ES Test Attachments

Error message
Expected string length 89 but was 67. Strings differ at index 36.
Expected: "...eption: Keystore was tampered with, or password was incorrect"
But was:  "...eption: keystore password was incorrect"
----------------------^

I think we can just update the assertion.

Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com>

Copilot AI commented Mar 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot there is one test failure:

ListInvalidPassword

...

Updated the assertion in 0937840. The PKCS12 format produces "keystore password was incorrect" instead of the JKS "Keystore was tampered with, or password was incorrect". Changed to Assert.That(error.Message, Does.Contain("password was incorrect")) so it works with both keystore formats.

@jonathanpeppers
jonathanpeppers merged commit 1bdbb4a into main Mar 13, 2026
6 checks passed
@jonathanpeppers
jonathanpeppers deleted the copilot/remove-test-keystore-file branch March 13, 2026 19:18
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove checked-in test.keystore and generate it dynamically during tests

3 participants