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

Add local testing mode to the buildmaster config #289

Merged
merged 3 commits into from
Nov 8, 2024
Merged
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
5 changes: 4 additions & 1 deletion buildbot/osuosl/master/config/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import config

def create_worker(name, *args, **kwargs):
password = config.options.get('Worker Passwords', name)
if config.options.getboolean('Internal', 'test_mode'):
password = "test"
else:
password = config.options.get('Worker Passwords', name)
return worker.Worker(name, password=password, *args, **kwargs)

def get_all():
Expand Down
37 changes: 24 additions & 13 deletions buildbot/osuosl/master/master.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,18 @@ c['buildbotNetUsageData'] = None
import config
reload(config)

# Detect if the BUILDMASTER_TEST environment variable is set and non-zero.
# This will be used to enable a local testing mode.
buildmaster_test = os.environ.get('BUILDMASTER_TEST')
test_mode = bool(buildmaster_test) and buildmaster_test != '0'
config.options['Internal'] = {}
config.options['Internal']['test_mode'] = str(test_mode)

####### Workers

c['workers'] = config.workers.get_all()

c['protocols'] = {'pb': {'port': 9990}}
c['protocols'] = {'pb': {'port': "tcp:9990:interface=127.0.0.1" if test_mode else 9990}}
Copy link
Contributor

Choose a reason for hiding this comment

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

I not 100% sure on this but I believe putting interface=127.0.0.1 will make test buildmaster inaccessible from the outside world which is not always the case. For example, if we are running this test master in a cloud vps and want our out of network workers to have access to it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's correct, my thinking is to default to something that's as secure as possible. I use ssh port forwarding in this case, but I think socat could also work if you just want to quickly expose the port to the outside world with no auth needed. Or of course editing the command line yourself.

I can document ssh port forwarding and/or socat for this and the web interface in the followon patch to https://llvm.org/docs/HowToAddABuilder.html that describes testing mode.

Perhaps I'm being over-cautious? But on the other hand:

  • This mode uses a default password for connections, meaning it's easy to connect to the buildmaster and thus exploitation is much more plausible vs a production buildmaster where attackers shouldn't be able to connect
  • People often run a mode like this on developer machines or within secure networks, so the potential impact is high vs a production buildmaster where (hopefully!) time and thought have gone into appropriate permissions / sandboxing / firewalling.
  • For most cases where you're interactively testing a buildmaster and set of builders, I'd imagine using ssh port forwarding does the job fine.

Anyway, that's my thinking - other suggestions welcome!


####### CHANGESOURCES

Expand Down Expand Up @@ -94,25 +101,29 @@ c['services'] = config.status.getReporters()

####### PROJECT IDENTITY

c['title'] = config.options.get('Buildbot', 'title')
c['titleURL'] = config.options.get('Buildbot', 'title_url')
c['buildbotURL'] = config.options.get('Buildbot', 'my_url')
c['title'] = "Buildbot (test)" if test_mode else config.options.get('Buildbot', 'title')
c['titleURL'] = "http://localhost:8011/" if test_mode else config.options.get('Buildbot', 'title_url')
c['buildbotURL'] = "http://localhost:8011/" if test_mode else config.options.get('Buildbot', 'my_url')

# minimalistic config to activate new web UI
c['www'] = dict(port=8011,
plugins=dict(waterfall_view={}, console_view={}, grid_view={}), # TODO: badges
default_page='console',
auth=config.auth.getAuth(),
authz=config.auth.getAuthz(),
#logRotateLength=
#maxRotatedFiles=
#versions=
www_config = dict(port="tcp:8011:interface=127.0.0.1" if test_mode else 8011,
plugins=dict(waterfall_view={}, console_view={}, grid_view={}), # TODO: badges
default_page='console',
#logRotateLength=
#maxRotatedFiles=
#versions=
)

if not test_mode:
Copy link
Contributor

Choose a reason for hiding this comment

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

If we dont get auth from github, does it mean that all worker are accessible to us or are there other changes required for allowing test buildmaster owner to be the owner of all the connected workers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Leaving out both auth and authz fields in the config dict seems to result in being able to access the web interface with no auth needed, and anyone accessing the interface being able to force builds and clear queues. Leaving out 'auth' but leaving in 'authz' means you can't do those commands.

Are there any other actions I might have missed I should test?

The buildbotURL also needs to be correct or else you get "invalid origin" errors when clicking those buttons in the web UI. This is another case ssh port forwarding helps if you happened to be testing on a server - as you can have it so localhost:8011 forwards to 8011 on the loopback interface on the remote machine.

www_config['auth'] = config.auth.getAuth()
www_config['authz'] = config.auth.getAuthz()

c['www'] = www_config

####### DB URL

c['db'] = {
'db_url' : config.options.get('Database', 'db_url'),
'db_url' : "sqlite:///state.sqlite" if test_mode else config.options.get('Database', 'db_url'),
}

####### RESOURCE USAGE
Expand Down