Bug 1557269 - part 2: GPG-sign geckoview artifacts r=mtabara
authorJohan Lorenzo <jlorenzo@mozilla.com>
Fri, 05 Jul 2019 15:19:00 +0000
changeset 541166 34e52d51840a433e51f1381b625bd233494bd7bb
parent 541165 178a2ab709eebee94aa64621823f6a65249c3d30
child 541167 06e0a127bc84ec22c2f537e8fec25e1705594070
push id11533
push userarchaeopteryx@coole-files.de
push dateMon, 08 Jul 2019 18:18:03 +0000
treeherdermozilla-beta@f4452e031aed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmtabara
bugs1557269
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1557269 - part 2: GPG-sign geckoview artifacts r=mtabara Differential Revision: https://phabricator.services.mozilla.com/D34866
taskcluster/ci/beetmover-geckoview/kind.yml
taskcluster/ci/build/android.yml
taskcluster/taskgraph/manifests/fennec_geckoview.yml
taskcluster/taskgraph/transforms/beetmover_geckoview.py
taskcluster/taskgraph/transforms/build_signing.py
taskcluster/taskgraph/transforms/nightly_l10n_signing.py
taskcluster/taskgraph/transforms/partner_signing.py
taskcluster/taskgraph/transforms/signing.py
taskcluster/taskgraph/util/attributes.py
taskcluster/taskgraph/util/declarative_artifacts.py
taskcluster/taskgraph/util/scriptworker.py
taskcluster/taskgraph/util/signed_artifacts.py
--- a/taskcluster/ci/beetmover-geckoview/kind.yml
+++ b/taskcluster/ci/beetmover-geckoview/kind.yml
@@ -5,17 +5,17 @@
 loader: taskgraph.loader.single_dep:loader
 
 transforms:
     - taskgraph.transforms.name_sanity:transforms
     - taskgraph.transforms.beetmover_geckoview:transforms
     - taskgraph.transforms.task:transforms
 
 kind-dependencies:
-    - build  # geckoview builds aren't signed
+    - build-signing
 
 only-for-attributes:
     - nightly
 
 not-for-build-platforms:
     - linux-nightly/opt
     - linux-shippable/opt
     - linux64-nightly/opt
@@ -35,17 +35,16 @@ not-for-build-platforms:
     - win64-devedition-nightly/opt
     - win64-aarch64-devedition-nightly/opt
     - linux64-asan-reporter-nightly/opt
     - win64-asan-reporter-nightly/opt
 
 job-template:
     attributes:
         artifact_map: taskcluster/taskgraph/manifests/fennec_geckoview.yml
-        artifact_prefix: public/build/maven
     run-on-projects: ['mozilla-central', 'mozilla-release']
     run-on-hg-branches:
         by-project:
             mozilla-release:
                 - '^GECKOVIEW_\d+_RELBRANCH$'
             default:
                 - '.*'
     shipping-phase:
--- a/taskcluster/ci/build/android.yml
+++ b/taskcluster/ci/build/android.yml
@@ -1,13 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 ---
 job-defaults:
+    attributes:
+        artifact_map: taskcluster/taskgraph/manifests/fennec_geckoview.yml
     index:
         product: mobile
     worker:
         docker-image: {in-tree: android-build}
         max-run-time: 7200
         env:
             GRADLE_USER_HOME: "/builds/worker/workspace/build/src/mobile/android/gradle/dotgradle-offline"
         artifacts:
@@ -548,17 +550,16 @@ android-geckoview-fat-aar/opt:
         - linux64-sccache
 
 android-geckoview-fat-aar-nightly/opt:
     description: "Android GeckoView multi-architecture fat AAR Nightly"
     attributes:
         nightly: true
         enable-full-crashsymbols: true
         disable-push-apk: true
-        disable-build-signing: true
     shipping-phase: build
     shipping-product: fennec
     index:
         job-name: android-geckoview-fat-aar-nightly
         type: nightly-with-multi-l10n
     treeherder:
         platform: android-4-0-geckoview-fat-aar/opt
         symbol: Ngv
--- a/taskcluster/taskgraph/manifests/fennec_geckoview.yml
+++ b/taskcluster/taskgraph/manifests/fennec_geckoview.yml
@@ -3,71 +3,101 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 ---
 s3_bucket_paths:
     - maven2
 default_locales:  # Ignored for geckoview
     - en-US
 tasktype_map:  # Map task reference to task type.
     build: build
-base_artifact_prefix: public/build/maven/
+    build-signing: signing
 
 # A default entry, which the mappings below extend and override.
 # Final 'destinations' will be the product of:
 # s3_bucket_paths + destinations + locale_prefix + pretty_name
 default: &default
-    from:
-        - build
     locale_prefix: ''
-    source_path_modifier: org/mozilla/geckoview/${artifact_id}/${major_version}.${minor_version}.${build_date}
+    source_path_modifier: maven/org/mozilla/geckoview/${artifact_id}/${major_version}.${minor_version}.${build_date}
     description: "TO_BE_OVERRIDDEN"
     destinations:  # locale_prefix is appended
         - org/mozilla/geckoview/${artifact_id}/${major_version}.${minor_version}.${build_date}
 
 mapping:
-    ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.sha1:
-        <<: *default
-        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.sha1
-        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.sha1
-    ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.md5:
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar:
         <<: *default
-        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.md5
-        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.md5
-    ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.sha1:
+        from: ['build']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.asc:
         <<: *default
-        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.sha1
-        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.sha1
+        from: ['build-signing']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.asc
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.asc
     ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.md5:
         <<: *default
+        from: ['build']
         pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.md5
         checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.md5
-    ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.sha1:
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.sha1:
+        <<: *default
+        from: ['build']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.sha1
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar.sha1
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom:
         <<: *default
-        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.sha1
-        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.sha1
-    ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar:
+        from: ['build']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.asc:
         <<: *default
-        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar
-        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar
+        from: ['build-signing']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.asc
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.asc
     ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.md5:
         <<: *default
+        from: ['build']
         pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.md5
         checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.md5
-    ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom:
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.sha1:
         <<: *default
-        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom
-        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom
-    ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar:
+        from: ['build']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.sha1
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.pom.sha1
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar:
         <<: *default
-        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar
-        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}.aar
-    ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.md5:
+        from: ['build']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.asc:
         <<: *default
-        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.md5
-        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.md5
+        from: ['build-signing']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.asc
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.asc
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.md5:
+        <<: *default
+        from: ['build']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.md5
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.md5
     ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.sha1:
         <<: *default
+        from: ['build']
         pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.sha1
         checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-javadoc.jar.sha1
     ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar:
         <<: *default
+        from: ['build']
         pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar
         checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.asc:
+        <<: *default
+        from: ['build-signing']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.asc
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.asc
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.md5:
+        <<: *default
+        from: ['build']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.md5
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.md5
+    ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.sha1:
+        <<: *default
+        from: ['build']
+        pretty_name: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.sha1
+        checksums_path: ${artifact_id}-${major_version}.${minor_version}.${build_date}-sources.jar.sha1
--- a/taskcluster/taskgraph/transforms/beetmover_geckoview.py
+++ b/taskcluster/taskgraph/transforms/beetmover_geckoview.py
@@ -2,47 +2,35 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 """
 Transform the beetmover task into an actual task description.
 """
 
 from __future__ import absolute_import, print_function, unicode_literals
 
-import re
+from copy import deepcopy
 
 from taskgraph.loader.single_dep import schema
 from taskgraph.transforms.base import TransformSequence
 from taskgraph.transforms.beetmover import \
     craft_release_properties as beetmover_craft_release_properties
 from taskgraph.util.attributes import copy_attributes_from_dependent_job
+from taskgraph.util.declarative_artifacts import (
+    get_geckoview_template_vars,
+    get_geckoview_upstream_artifacts,
+    get_geckoview_artifact_id,
+)
 from taskgraph.util.schema import resolve_keyed_by, optionally_keyed_by
 from taskgraph.util.scriptworker import (generate_beetmover_artifact_map,
-                                         generate_beetmover_upstream_artifacts,
                                          get_worker_type_for_scope)
 from taskgraph.transforms.task import task_description_schema
 from voluptuous import Required, Optional
 
 
-_ARTIFACT_ID_PER_PLATFORM = {
-    'android-aarch64': 'geckoview{update_channel}-arm64-v8a',
-    'android-api-16': 'geckoview{update_channel}-armeabi-v7a',
-    'android-x86': 'geckoview{update_channel}-x86',
-    'android-x86_64': 'geckoview{update_channel}-x86_64',
-    'android-geckoview-fat-aar': 'geckoview{update_channel}',
-}
-
-_MOZ_UPDATE_CHANNEL_PER_BRANCH = {
-    'mozilla-release': '',
-    'mozilla-beta': '-beta',
-    'mozilla-central': '-nightly',
-    'try': '-nightly-try',
-    'maple': '-nightly-maple',
-}
-
 beetmover_description_schema = schema.extend({
     Required('depname', default='build'): basestring,
     Optional('label'): basestring,
     Optional('treeherder'): task_description_schema['treeherder'],
 
     Required('run-on-projects'): task_description_schema['run-on-projects'],
     Required('run-on-hg-branches'): task_description_schema['run-on-hg-branches'],
 
@@ -92,17 +80,18 @@ def make_task_description(config, jobs):
         description = (
             "Beetmover submission for geckoview"
             "{build_platform}/{build_type}'".format(
                 build_platform=attributes.get('build_platform'),
                 build_type=attributes.get('build_type')
             )
         )
 
-        dependencies = {dep_job.kind: dep_job.label}
+        dependencies = deepcopy(dep_job.dependencies)
+        dependencies[dep_job.kind] = dep_job.label
 
         attributes = copy_attributes_from_dependent_job(dep_job)
         attributes.update(job.get('attributes', {}))
 
         if job.get('locale'):
             attributes['locale'] = job['locale']
 
         attributes['run_on_hg_branches'] = job['run-on-hg-branches']
@@ -120,59 +109,40 @@ def make_task_description(config, jobs):
         }
 
         yield task
 
 
 @transforms.add
 def make_task_worker(config, jobs):
     for job in jobs:
-        valid_beetmover_job = len(job['dependencies']) == 1 and 'build' in job['dependencies']
+        valid_beetmover_job = set(job['dependencies'].keys()) == {'build', 'build-signing'}
         if not valid_beetmover_job:
             raise NotImplementedError(
-                'Beetmover-geckoview must have a single dependency. Got: {}'.format(
+                'Beetmover-geckoview must have 2 dependencies: build and build-signing. '
+                'Got: {}'.format(
                     job['dependencies']
                 )
             )
 
-        worker = {
+        job['worker'] = {
+            'artifact-map': generate_beetmover_artifact_map(
+                config,
+                job,
+                **get_geckoview_template_vars(config, job['attributes']['build_platform'])
+            ),
             'implementation': 'beetmover-maven',
             'release-properties': craft_release_properties(config, job),
-        }
-
-        version_groups = re.match(r'(\d+).(\d+).*', config.params['version'])
-        if version_groups:
-            major_version, minor_version = version_groups.groups()
-
-        template_vars = {
-            'artifact_id': worker['release-properties']['artifact-id'],
-            'build_date': config.params['moz_build_date'],
-            'major_version': major_version,
-            'minor_version': minor_version,
+            'upstream-artifacts': get_geckoview_upstream_artifacts(config, job),
         }
-        worker['artifact-map'] = generate_beetmover_artifact_map(
-            config, job, **template_vars
-        )
-        upstream_artifacts = generate_beetmover_upstream_artifacts(
-            config, job, platform='', **template_vars
-        )
-        worker['upstream-artifacts'] = [{
-            key: value for key, value in upstream_artifact.items()
-            if key != 'locale'
-        } for upstream_artifact in upstream_artifacts]
-
-        job["worker"] = worker
 
         yield job
 
 
 def craft_release_properties(config, job):
-    props = beetmover_craft_release_properties(config, job)
+    release_properties = beetmover_craft_release_properties(config, job)
 
-    platform = props['platform']
-    update_channel = _MOZ_UPDATE_CHANNEL_PER_BRANCH.get(
-        props['branch'], '-UNKNOWN_MOZ_UPDATE_CHANNEL'
+    release_properties['artifact-id'] = get_geckoview_artifact_id(
+        job['attributes']['build_platform'], release_properties['branch']
     )
-    artifact_id = _ARTIFACT_ID_PER_PLATFORM[platform].format(update_channel=update_channel)
-    props['artifact-id'] = artifact_id
-    props['app-name'] = 'geckoview'     # this beetmover job is not about pushing Fennec
+    release_properties['app-name'] = 'geckoview'
 
-    return props
+    return release_properties
--- a/taskcluster/taskgraph/transforms/build_signing.py
+++ b/taskcluster/taskgraph/transforms/build_signing.py
@@ -3,16 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 """
 Transform the signing task into an actual task description.
 """
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 from taskgraph.transforms.base import TransformSequence
+from taskgraph.util.attributes import copy_attributes_from_dependent_job
 from taskgraph.util.signed_artifacts import generate_specifications_of_artifacts_to_sign
 from taskgraph.util.taskcluster import get_artifact_path
 
 
 transforms = TransformSequence()
 
 
 @transforms.add
@@ -45,18 +46,21 @@ def add_signed_routes(config, jobs):
 
 
 @transforms.add
 def define_upstream_artifacts(config, jobs):
     for job in jobs:
         dep_job = job['primary-dependency']
         build_platform = dep_job.attributes.get('build_platform')
 
+        job['attributes'] = copy_attributes_from_dependent_job(dep_job)
+
         artifacts_specifications = generate_specifications_of_artifacts_to_sign(
-            dep_job,
+            config,
+            job,
             keep_locale_template=False,
             kind=config.kind,
         )
 
         if 'android' in build_platform:
             # We're in the job that creates both multilocale and en-US APKs
             artifacts_specifications[0]['artifacts'].append(
                 get_artifact_path(dep_job, 'en-US/target.apk')
--- a/taskcluster/taskgraph/transforms/nightly_l10n_signing.py
+++ b/taskcluster/taskgraph/transforms/nightly_l10n_signing.py
@@ -3,16 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 """
 Transform the signing task into an actual task description.
 """
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 from taskgraph.transforms.base import TransformSequence
+from taskgraph.util.attributes import copy_attributes_from_dependent_job
 from taskgraph.util.signed_artifacts import generate_specifications_of_artifacts_to_sign
 from taskgraph.util.treeherder import join_symbol
 
 transforms = TransformSequence()
 
 
 @transforms.add
 def make_signing_description(config, jobs):
@@ -32,18 +33,21 @@ def make_signing_description(config, job
         yield job
 
 
 @transforms.add
 def define_upstream_artifacts(config, jobs):
     for job in jobs:
         dep_job = job['primary-dependency']
 
+        job['attributes'] = copy_attributes_from_dependent_job(dep_job)
+
         locale_specifications = generate_specifications_of_artifacts_to_sign(
-            dep_job,
+            config,
+            job,
             keep_locale_template=True,
         )
 
         upstream_artifacts = []
         for spec in locale_specifications:
             upstream_artifacts.append({
                 'taskId': {'task-reference': '<unsigned-repack>'},
                 'taskType': 'l10n',
--- a/taskcluster/taskgraph/transforms/partner_signing.py
+++ b/taskcluster/taskgraph/transforms/partner_signing.py
@@ -21,16 +21,17 @@ def define_upstream_artifacts(config, jo
     partner_configs = get_partner_config_by_kind(config, config.kind)
     if not partner_configs:
         return
 
     for job in jobs:
         dep_job = job['primary-dependency']
         repack_id = job['extra']['repack_id']
         artifacts_specifications = generate_specifications_of_artifacts_to_sign(
+            config,
             dep_job,
             keep_locale_template=True,
             kind=config.kind,
         )
         job['upstream-artifacts'] = [{
             'taskId': {'task-reference': '<{}>'.format(job['depname'])},
             'taskType': 'build',
             'paths': [
--- a/taskcluster/taskgraph/transforms/signing.py
+++ b/taskcluster/taskgraph/transforms/signing.py
@@ -37,16 +37,19 @@ signing_description_schema = schema.exte
 
         # Signing formats to use on each of the paths
         Required('formats'): [basestring],
     }],
 
     # depname is used in taskref's to identify the taskID of the unsigned things
     Required('depname'): basestring,
 
+    # attributes for this task
+    Optional('attributes'): {basestring: object},
+
     # unique label to describe this signing task, defaults to {dep.label}-signing
     Optional('label'): basestring,
 
     # treeherder is allowed here to override any defaults we use for signing.  See
     # taskcluster/taskgraph/transforms/task.py for the schema details, and the
     # below transforms for defaults of various values.
     Optional('treeherder'): task_description_schema['treeherder'],
 
@@ -132,17 +135,18 @@ def make_task_description(config, jobs):
             "Initial Signing for locale '{locale}' for build '"
             "{build_platform}/{build_type}'".format(
                 locale=attributes.get('locale', 'en-US'),
                 build_platform=build_platform,
                 build_type=attributes.get('build_type')
             )
         )
 
-        attributes = copy_attributes_from_dependent_job(dep_job)
+        attributes = job['attributes'] if job.get('attributes') else \
+            copy_attributes_from_dependent_job(dep_job)
         attributes['signed'] = True
 
         if dep_job.attributes.get('chunk_locales'):
             # Used for l10n attribute passthrough
             attributes['chunk_locales'] = dep_job.attributes.get('chunk_locales')
 
         signing_cert_scope = get_signing_cert_scope_per_platform(
             build_platform, is_nightly, config
--- a/taskcluster/taskgraph/util/attributes.py
+++ b/taskcluster/taskgraph/util/attributes.py
@@ -30,16 +30,17 @@ RELEASE_PROJECTS = {
 RELEASE_PROMOTION_PROJECTS = {
     'jamun',
     'maple',
     'try',
     'try-comm-central',
 } | RELEASE_PROJECTS
 
 _OPTIONAL_ATTRIBUTES = (
+    'artifact_map',
     'artifact_prefix',
     'l10n_chunk',
     'locale',
     'nightly',
     'required_signoffs',
     'signed',
     'shipping_phase',
     'shipping_product',
new file mode 100644
--- /dev/null
+++ b/taskcluster/taskgraph/util/declarative_artifacts.py
@@ -0,0 +1,51 @@
+from __future__ import absolute_import, unicode_literals
+
+import re
+
+from taskgraph.util.scriptworker import generate_beetmover_upstream_artifacts
+
+
+_ARTIFACT_ID_PER_PLATFORM = {
+    'android-aarch64-nightly': 'geckoview{update_channel}-arm64-v8a',
+    'android-api-16-nightly': 'geckoview{update_channel}-armeabi-v7a',
+    'android-x86-nightly': 'geckoview{update_channel}-x86',
+    'android-x86_64-nightly': 'geckoview{update_channel}-x86_64',
+    'android-geckoview-fat-aar-nightly': 'geckoview{update_channel}',
+}
+
+_MOZ_UPDATE_CHANNEL_PER_PROJECT = {
+    'mozilla-release': '',
+    'mozilla-beta': '-beta',
+    'mozilla-central': '-nightly',
+    'try': '-nightly-try',
+    'maple': '-nightly-maple',
+}
+
+
+def get_geckoview_upstream_artifacts(config, job):
+    upstream_artifacts = generate_beetmover_upstream_artifacts(
+        config, job, platform='',
+        **get_geckoview_template_vars(config, job['attributes']['build_platform'])
+    )
+    return [{
+        key: value for key, value in upstream_artifact.items()
+        if key != 'locale'
+    } for upstream_artifact in upstream_artifacts]
+
+
+def get_geckoview_template_vars(config, platform):
+    version_groups = re.match(r'(\d+).(\d+).*', config.params['version'])
+    if version_groups:
+        major_version, minor_version = version_groups.groups()
+
+    return {
+        'artifact_id': get_geckoview_artifact_id(platform, config.params['project']),
+        'build_date': config.params['moz_build_date'],
+        'major_version': major_version,
+        'minor_version': minor_version,
+    }
+
+
+def get_geckoview_artifact_id(platform, project):
+    update_channel = _MOZ_UPDATE_CHANNEL_PER_PROJECT.get(project, '-UNKNOWN_MOZ_UPDATE_CHANNEL')
+    return _ARTIFACT_ID_PER_PLATFORM[platform].format(update_channel=update_channel)
--- a/taskcluster/taskgraph/util/scriptworker.py
+++ b/taskcluster/taskgraph/util/scriptworker.py
@@ -440,17 +440,22 @@ def generate_beetmover_upstream_artifact
     if not locale:
         locales = map_config['default_locales']
     elif isinstance(locale, list):
         locales = locale
     else:
         locales = [locale]
 
     if not dependencies:
-        dependencies = job['dependencies'].keys()
+        if job.get('dependencies'):
+            dependencies = job['dependencies'].keys()
+        elif job.get('primary-dependency'):
+            dependencies = [job['primary-dependency'].kind]
+        else:
+            raise Exception('Unsupported type of dependency. Got job: {}'.format(job))
 
     for locale, dep in itertools.product(locales, dependencies):
         paths = list()
 
         for filename in map_config['mapping']:
             if dep not in map_config['mapping'][filename]['from']:
                 continue
             if locale != 'en-US' and not map_config['mapping'][filename]['all_locales']:
@@ -471,20 +476,24 @@ def generate_beetmover_upstream_artifact
             kwargs['locale'] = locale
 
             paths.append(os.path.join(
                 base_artifact_prefix,
                 jsone.render(file_config['source_path_modifier'], kwargs),
                 jsone.render(filename, kwargs),
             ))
 
-        if getattr(job['dependencies'][dep], 'release_artifacts', None):
+        if (
+            job.get('dependencies') and
+            getattr(job['dependencies'][dep], 'release_artifacts', None)
+        ):
             paths = [
                 path for path in paths
-                if path in job['dependencies'][dep].release_artifacts]
+                if path in job['dependencies'][dep].release_artifacts
+            ]
 
         if not paths:
             continue
 
         upstream_artifacts.append({
             "taskId": {
                 "task-reference": "<{}>".format(dep)
             },
--- a/taskcluster/taskgraph/util/signed_artifacts.py
+++ b/taskcluster/taskgraph/util/signed_artifacts.py
@@ -2,73 +2,77 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 """
 Defines artifacts to sign before repackage.
 """
 
 from __future__ import absolute_import, print_function, unicode_literals
 from taskgraph.util.taskcluster import get_artifact_path
+from taskgraph.util.declarative_artifacts import get_geckoview_upstream_artifacts
 
 
 def is_partner_kind(kind):
     if kind and kind.startswith(('release-partner', 'release-eme-free')):
         return True
 
 
 def generate_specifications_of_artifacts_to_sign(
-    task, keep_locale_template=True, kind=None
+    config, job, keep_locale_template=True, kind=None
 ):
-    build_platform = task.attributes.get('build_platform')
-    use_stub = task.attributes.get('stub-installer')
+    build_platform = job['attributes'].get('build_platform')
+    use_stub = job['attributes'].get('stub-installer')
     if kind == 'release-source-signing':
         artifacts_specifications = [{
             'artifacts': [
-                get_artifact_path(task, 'source.tar.xz')
+                get_artifact_path(job, 'source.tar.xz')
             ],
             'formats': ['autograph_gpg'],
         }]
     elif 'android' in build_platform:
         artifacts_specifications = [{
             'artifacts': [
-                get_artifact_path(task, '{locale}/target.apk'),
+                get_artifact_path(job, '{locale}/target.apk'),
             ],
             'formats': ['autograph_apk_fennec_sha1'],
+        }, {
+            'artifacts': get_geckoview_artifacts_to_sign(config, job),
+            'formats': ['autograph_gpg'],
         }]
     # XXX: Mars aren't signed here (on any platform) because internals will be
     # signed at after this stage of the release
     elif 'macosx' in build_platform:
         if is_partner_kind(kind):
             extension = 'tar.gz'
         else:
             extension = 'dmg'
         artifacts_specifications = [{
-            'artifacts': [get_artifact_path(task, '{{locale}}/target.{}'.format(extension))],
+            'artifacts': [get_artifact_path(job, '{{locale}}/target.{}'.format(extension))],
             'formats': ['macapp', 'autograph_widevine', 'autograph_omnija'],
         }]
     elif 'win' in build_platform:
         artifacts_specifications = [{
             'artifacts': [
-                get_artifact_path(task, '{locale}/setup.exe'),
+                get_artifact_path(job, '{locale}/setup.exe'),
             ],
             'formats': ['sha2signcode'],
         }, {
             'artifacts': [
-                get_artifact_path(task, '{locale}/target.zip'),
+                get_artifact_path(job, '{locale}/target.zip'),
             ],
             'formats': ['sha2signcode', 'autograph_widevine', 'autograph_omnija'],
         }]
 
         if use_stub:
             artifacts_specifications[0]['artifacts'] += [
-                get_artifact_path(task, '{locale}/setup-stub.exe')
+                get_artifact_path(job, '{locale}/setup-stub.exe')
             ]
     elif 'linux' in build_platform:
         artifacts_specifications = [{
-            'artifacts': [get_artifact_path(task, '{locale}/target.tar.bz2')],
+            'artifacts': [get_artifact_path(job, '{locale}/target.tar.bz2')],
             'formats': ['autograph_gpg', 'autograph_widevine', 'autograph_omnija'],
         }]
     else:
         raise Exception("Platform not implemented for signing")
 
     if not keep_locale_template:
         artifacts_specifications = _strip_locale_template(artifacts_specifications)
 
@@ -112,8 +116,18 @@ def get_signed_artifacts(input, formats,
         if behavior and behavior != "mac_sign":
             artifacts.add(input.replace('.dmg', '.pkg'))
     else:
         artifacts.add(input)
     if 'autograph_gpg' in formats:
         artifacts.add('{}.asc'.format(input))
 
     return artifacts
+
+
+def get_geckoview_artifacts_to_sign(config, job):
+    upstream_artifacts = get_geckoview_upstream_artifacts(config, job)
+    return [
+        path
+        for upstream_artifact in upstream_artifacts
+        for path in upstream_artifact['paths']
+        if not path.endswith('.md5') and not path.endswith('.sha1')
+    ]