Skip to content
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

Mock the daemon and run tests against prod builds #9584

Merged
merged 33 commits into from
Jun 25, 2024
Merged

Conversation

oskirby
Copy link
Collaborator

@oskirby oskirby commented May 18, 2024

Description

This is something of a hobby project. The end goal is to try and run functional tests against production builds of the VPN client, and to get there we need a way to mock out the controller a little better. The first checkpoint of which is to write a mock daemon and replace the DummyController with it.

Roughly speaking a high-level change log for this effort goes like this:

  1. Implement a new MockDaemon class that mocks out the daemon APIs and creates a local socket server.
  2. Replace the DummyController with a LocalSocketController that talks to the mocked daemon.
  3. Extend the --testing option to automatically create the mock daemon.
  4. Add a feature to disable Balrog.
  5. Try to replace all #ifdef MZ_DUMMY with runtime switches triggered by --testing:

Then to get tests working on the production builds, we need to extend the --testing option to make the prod build act like the dummy build:

  • Disable cryptosettings.
  • Disable/reset glean telemetry.
  • Mock out the AppListProvider class.
  • Use a different settings file.

Reference

This is a prerequisite for the following JIRA tasks

  • VPN-5768 - Automate functional tests for Windows
  • VPN-3077 - Automate functional tests for iOS/Android

Checklist

  • My code follows the style guidelines for this project
  • I have not added any packages that contain high risk or unknown licenses (GPL, LGPL, MPL, etc. consult with DevOps if in question)
  • I have performed a self review of my own code
  • I have commented my code PARTICULARLY in hard to understand areas
  • I have added thorough tests where needed
@oskirby oskirby changed the title Mock the daemon instead of using a DummyController May 20, 2024
@oskirby oskirby force-pushed the mock-daemon-round2 branch 3 times, most recently from 153e0b7 to 40b3c98 Compare June 15, 2024 21:14
@oskirby oskirby marked this pull request as ready for review June 17, 2024 21:31
Copy link
Collaborator

@strseb strseb left a comment

Choose a reason for hiding this comment

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

FANCY!

Copy link
Collaborator

@mcleinman mcleinman left a comment

Choose a reason for hiding this comment

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

Thanks for this! Lots of questions, but all to make sure I better understand what I'm approving here.

src/localsocketcontroller.cpp Show resolved Hide resolved
src/glean/mzglean.cpp Show resolved Hide resolved
LogHandler::setStderr(true);

// Disable encrypted settings for testing.
CryptoSettings::mock();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Apologies for my lack of understanding - why can't we have encryption on our dummy builds?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This was done for MacOS (and presumably iOS too?) - access to platform secrets is something that requires a signed executable, and we don't want to require codesigning to run tests. It used to be that the Crypto settings for MacOS were no-ops when compiled with MZ_DUMMY so this just kind of made it consistent for all platforms.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

After a bit of research, I think we could put this back if we add a check to disable crypto settings if the codesign is invalid on MacOS. Something to the tune of:

#include <sys/codesign.h>

MacOSCryptoSettings::MacOSCryptoSettings() : CryptoSettings() {
  int flags = 0;
  if ((csopts(getpid(), CS_OP_STATUS, &flags, sizeof(flags) == 0) && (flags & CS_VALID)) {
    m_keyVersion = CryptoSettings::EncryptedChachaPolyV1;
  } else {
    m_keyVersion = CryptoSettings::NoEncryption;
  }
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would that mean if somone bitflips a thing in our binary, therefore breaking codesign we would just disable encyption?
I actually like the specific-opt in :D

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I prefer it to be aligned with code signing instead of a compile flag. Thinking about the ways a hidden adversary could exploit this down the line, it seems more likely to get a "build with a testing flag" out into prod than a "build that wasn't codesigned".

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree, it sounds much better to disarm the cryptosettings by checking for valid codesignatures.

Joke is on me though - we kind of all agree that it should be done this way... but it's actually turning out to be hard to do.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I did it! See the PR here: #9679

Once that one is merged, I will rebase this and undo the crypto settings mocks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Rebase complete!

src/commandlineparser.cpp Show resolved Hide resolved
src/platforms/linux/linuxdependencies.cpp Show resolved Hide resolved
src/daemon/daemon.cpp Show resolved Hide resolved
Copy link
Collaborator

@mcleinman mcleinman left a comment

Choose a reason for hiding this comment

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

Thanks! Just one more thing before I feel comfortable approving.

LogHandler::setStderr(true);

// Disable encrypted settings for testing.
CryptoSettings::mock();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I prefer it to be aligned with code signing instead of a compile flag. Thinking about the ways a hidden adversary could exploit this down the line, it seems more likely to get a "build with a testing flag" out into prod than a "build that wasn't codesigned".

src/glean/mzglean.cpp Show resolved Hide resolved
Normally we don't notice this bug because of queueing delays, but the
deactivation isnt actually finished at the time when we emit this signal.
This was causing issues in the WASM client because it doesn't have
threading, meaning that it wound up processing the deactivate signal out
of order.
This eliminates the need to hardcode a settings filename for MZ_DUMMY.
When trying to run functional tests against a production client - we can't
presume that it's enabled by default as most prod clients use browser auth.
Copy link
Collaborator

@mcleinman mcleinman left a comment

Choose a reason for hiding this comment

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

👍🏻 Thanks!

@oskirby oskirby merged commit 2c0ca14 into main Jun 25, 2024
116 checks passed
@oskirby oskirby deleted the mock-daemon-round2 branch June 25, 2024 20:49
@oskirby oskirby mentioned this pull request Jul 17, 2024
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants