[IMP] runbot: add secret environment variables

Adds secret variables in addition to publicly readable ones, to
be able to provide ultra secret information to our builds without
requiring custom python code.
This commit is contained in:
William Braeckman 2025-03-11 16:24:06 +01:00
parent e44ac41a19
commit cc7ed99ceb
3 changed files with 44 additions and 5 deletions

View File

@ -159,6 +159,7 @@ class ConfigStep(models.Model):
sub_command = fields.Char('Subcommand', tracking=True)
extra_params = fields.Char('Extra cmd args', tracking=True)
additionnal_env = fields.Char('Extra env', help='Example: foo="bar";bar="foo". Cannot contains \' ', tracking=True)
secret_env = fields.Char('Secret env', help='Hidden environment variables\nExample: foo="bar";bar="foo". Cannot contain \' ', groups="runbot.group_runbot_admin")
enable_log_db = fields.Boolean("Enable log db", default=True)
demo_mode = fields.Selection(
[('default', 'Default'), ('without_demo', 'Without Demo'), ('with_demo', 'With Demo')],
@ -269,6 +270,18 @@ class ConfigStep(models.Model):
_logger.log('%s tried to create an non supported test_param %s' % (self.env.user.name, values.get('extra_params')))
raise UserError('Invalid extra_params on config step')
def _get_env_variables(self, build=None) -> list[str]:
"""Returns a list of environment variables in the format KEY=VALUE"""
self.ensure_one()
variables = []
if self.additionnal_env:
variables.extend(self.additionnal_env.split(';'))
if self.secret_env:
variables.extend(self.secret_env.split(';'))
if build and (config_env_variables := build.params_id.config_data.get('env_variables', False)):
variables.extend(config_env_variables.split(';'))
return variables
def _run(self, build):
build.write({'job_start': now(), 'job_end': False}) # state, ...
log = build._log('run', f'Starting step **{self.name}** from config **{build.params_id.config_id.name}**', log_type='markdown', level='SEPARATOR')
@ -405,7 +418,7 @@ class ConfigStep(models.Model):
extra_params = self.extra_params or ''
if extra_params:
cmd.extend(shlex.split(extra_params))
env_variables = self.additionnal_env.split(';') if self.additionnal_env else []
env_variables = self._get_env_variables(build=build)
build_port = build.port
try:
@ -508,9 +521,7 @@ class ConfigStep(models.Model):
if self.flamegraph:
cmd.finals.append(['flamegraph.pl', '--title', 'Flamegraph %s for build %s' % (self.name, build.id), self._perfs_data_path(), '>', self._perfs_data_path(ext='svg')])
cmd.finals.append(['gzip', '-f', self._perfs_data_path()]) # keep data but gz them to save disc space
env_variables = self.additionnal_env.split(';') if self.additionnal_env else []
if config_env_variables := build.params_id.config_data.get('env_variables', False):
env_variables += config_env_variables.split(';')
env_variables = self._get_env_variables(build=build)
return dict(cmd=cmd, ro_volumes=exports, env_variables=env_variables)
def _upgrade_create_childs(self):
@ -789,7 +800,7 @@ class ConfigStep(models.Model):
migrate_cmd.finals.append(['psql', migrate_db_name, '-c', '"SELECT id, name, state FROM ir_module_module WHERE state NOT IN (\'installed\', \'uninstalled\', \'uninstallable\') AND name NOT LIKE \'test_%\' "', '>', '/data/build/logs/modules_states.txt'])
env_variables = self.additionnal_env.split(';') if self.additionnal_env else []
env_variables = self._get_env_variables(build=build)
exception_env = self.env['runbot.upgrade.exception']._generate()
if exception_env:
env_variables.append(exception_env)

View File

@ -548,10 +548,37 @@ class TestBuildConfigStep(TestBuildConfigStepCommon):
child = self.parent_build._add_child({'config_data': {'env_variables': 'CHROME_CPU_THROTTLE=10'}})
env_variables = config_step._get_env_variables(build=child)
self.assertEqual(env_variables, ['CHROME_CPU_THROTTLE=10'])
params = config_step._run_install_odoo(child)
env_variables = params.get('env_variables', [])
self.assertEqual(env_variables, ['CHROME_CPU_THROTTLE=10'])
@patch('odoo.addons.runbot.models.build.BuildResult._parse_config')
@patch('odoo.addons.runbot.models.build.BuildResult._checkout')
def test_config_env_variables(self, mock_checkout, parse_config):
parse_config.return_value = {'--test-enable', '--test-tags'}
config_step = self.ConfigStep.create({
'name': 'all',
'job_type': 'install_odoo',
'additionnal_env': 'CONFIG=1;CONFIG_2=2',
'secret_env': 'SECRET=secret',
})
child = self.parent_build._add_child({'config_data': {'env_variables': 'BUILD=FOO'}})
env_variables = config_step._get_env_variables(build=child)
self.assertEqual(
env_variables,
[
'CONFIG=1',
'CONFIG_2=2',
'SECRET=secret',
'BUILD=FOO',
],
)
@patch('odoo.addons.runbot.models.build.BuildResult._checkout')
def test_db_name(self, mock_checkout):
config_step = self.ConfigStep.create({

View File

@ -78,6 +78,7 @@
<group string="Extra Parameters" invisible="job_type not in ('python', 'install_odoo', 'test_upgrade', 'run_odoo')">
<field name="extra_params"/>
<field name="additionnal_env"/>
<field name="secret_env"/>
<field name="enable_log_db"/>
</group>
<group string="Create settings" invisible="job_type not in ('python', 'create_build')">