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