1#!/usr/bin/env python 2# ***** BEGIN LICENSE BLOCK ***** 3# This Source Code Form is subject to the terms of the Mozilla Public 4# License, v. 2.0. If a copy of the MPL was not distributed with this file, 5# You can obtain one at http://mozilla.org/MPL/2.0/. 6# ***** END LICENSE BLOCK ***** 7"""Support for fetching secrets from the secrets API 8""" 9 10import os 11import mozharness 12import urllib2 13import json 14from mozharness.base.log import ERROR 15 16 17class SecretsMixin(object): 18 19 def _fetch_secret(self, secret_name): 20 self.info("fetching secret {} from API".format(secret_name)) 21 # fetch from http://taskcluster, which points to the taskcluster proxy 22 # within a taskcluster task. Outside of that environment, do not 23 # use this action. 24 url = "http://taskcluster/secrets/v1/secret/" + secret_name 25 res = urllib2.urlopen(url) 26 if res.getcode() != 200: 27 self.fatal("Error fetching from secrets API:" + res.read()) 28 29 return json.load(res)['secret']['content'] 30 31 def get_secrets(self): 32 """ 33 Get the secrets specified by the `secret_files` configuration. This is 34 a list of dictionaries, one for each secret. The `secret_name` key 35 names the key in the TaskCluster secrets API to fetch (see 36 http://docs.taskcluster.net/services/secrets/). It can contain 37 %-substitutions based on the `subst` dictionary below. 38 39 Since secrets must be JSON objects, the `content` property of the 40 secret is used as the value to be written to disk. 41 42 The `filename` key in the dictionary gives the filename to which the 43 secret should be written. 44 45 The optional `min_scm_level` key gives a minimum SCM level at which this 46 secret is required. For lower levels, the value of the 'default` key 47 is used, or no secret is written. 48 """ 49 if self.config.get('forced_artifact_build'): 50 self.info('Skipping due to forced artifact build.') 51 return 52 53 secret_files = self.config.get('secret_files', []) 54 55 scm_level = self.config.get('scm-level', 1) 56 subst = { 57 'scm-level': scm_level, 58 } 59 60 for sf in secret_files: 61 filename = sf['filename'] 62 secret_name = sf['secret_name'] % subst 63 min_scm_level = sf.get('min_scm_level', 0) 64 if scm_level <= min_scm_level: 65 if 'default' in sf: 66 self.info("Using default value for " + filename) 67 secret = sf['default'] 68 else: 69 self.info("No default for secret; not writing " + filename) 70 continue 71 else: 72 secret = self._fetch_secret(secret_name) 73 74 open(filename, "w").write(secret) 75