[assembly][build] Release partition configs.

Allow partitions to be released by specifying the cipd base url via
fuchsia_spec.build.partitions_cipd_release.

All partitions specified by the `partitions` build API module will be
published under that cipd prefix.

Bug: 344634556
Change-Id: I89bc4ee452a20048bbe14e222c80b8b59ad5a27c
Reviewed-on: https://fuchsia-review.googlesource.com/c/infra/recipes/+/1063492
Reviewed-by: Aidan Wolter <awolter@google.com>
Reviewed-by: Oliver Newman <olivernewman@google.com>
Commit-Queue: Darren Chan <chandarren@google.com>
diff --git a/recipe_modules/build/api.py b/recipe_modules/build/api.py
index 01474d3..06a516f 100644
--- a/recipe_modules/build/api.py
+++ b/recipe_modules/build/api.py
@@ -40,6 +40,7 @@
 RBE_CONFIG_JSON = "rbe_config.json"
 TOOL_PATHS_JSON = "tool_paths.json"
 PACKAGE_ARCHIVES_JSON = "package_archives.json"
+PARTITIONS_JSON = "partitions.json"
 TRIAGE_SOURCES_JSON = "triage_sources.json"
 VNAMES_CONFIG_JSON = "vnames_config.json"
 
@@ -278,6 +279,25 @@
         return {board["name"]: self.build_dir / board["outdir"] for board in boards}
 
     @functools.cached_property
+    def partitions(self):
+        """Parses the `partitions` build api module to create a mapping of
+        partitions configuration names to their paths.
+
+        Returns:
+            A mapping of released partition configuration name to absolute
+            artifact path.
+        """
+        partitions = self._api.file.read_json(
+            f"read {PARTITIONS_JSON}",
+            self.build_dir / PARTITIONS_JSON,
+            test_data=[{"name": "foo", "outdir": "obj/foo-partition"}],
+        )
+        return {
+            partition["name"]: self.build_dir / partition["outdir"]
+            for partition in partitions
+        }
+
+    @functools.cached_property
     def generated_sources(self):
         """The paths to the generated source files relative to the checkout root."""
         generated_sources = []
diff --git a/recipe_modules/build/tests/full.expected/default.json b/recipe_modules/build/tests/full.expected/default.json
index 7a02e32..d591805 100644
--- a/recipe_modules/build/tests/full.expected/default.json
+++ b/recipe_modules/build/tests/full.expected/default.json
@@ -3454,6 +3454,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/default_cq.json b/recipe_modules/build/tests/full.expected/default_cq.json
index 33fd220..19a3057 100644
--- a/recipe_modules/build/tests/full.expected/default_cq.json
+++ b/recipe_modules/build/tests/full.expected/default_cq.json
@@ -3555,6 +3555,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/duplicate_package_archive.json b/recipe_modules/build/tests/full.expected/duplicate_package_archive.json
index db9edf6..08ea959 100644
--- a/recipe_modules/build/tests/full.expected/duplicate_package_archive.json
+++ b/recipe_modules/build/tests/full.expected/duplicate_package_archive.json
@@ -3454,6 +3454,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/extract_artifacts.json b/recipe_modules/build/tests/full.expected/extract_artifacts.json
index 44b2224..0e804c9 100644
--- a/recipe_modules/build/tests/full.expected/extract_artifacts.json
+++ b/recipe_modules/build/tests/full.expected/extract_artifacts.json
@@ -3454,6 +3454,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/generate_skipped_shards.json b/recipe_modules/build/tests/full.expected/generate_skipped_shards.json
index f24fb30..4735a7b 100644
--- a/recipe_modules/build/tests/full.expected/generate_skipped_shards.json
+++ b/recipe_modules/build/tests/full.expected/generate_skipped_shards.json
@@ -3454,6 +3454,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/mac__release_version.json b/recipe_modules/build/tests/full.expected/mac__release_version.json
index d3d2813..7894f6d 100644
--- a/recipe_modules/build/tests/full.expected/mac__release_version.json
+++ b/recipe_modules/build/tests/full.expected/mac__release_version.json
@@ -3192,6 +3192,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/ninjatrace_fails.json b/recipe_modules/build/tests/full.expected/ninjatrace_fails.json
index 4b635c7..8982a29 100644
--- a/recipe_modules/build/tests/full.expected/ninjatrace_fails.json
+++ b/recipe_modules/build/tests/full.expected/ninjatrace_fails.json
@@ -3424,6 +3424,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/no_goma.json b/recipe_modules/build/tests/full.expected/no_goma.json
index 1e0cd73..83cc14e 100644
--- a/recipe_modules/build/tests/full.expected/no_goma.json
+++ b/recipe_modules/build/tests/full.expected/no_goma.json
@@ -2005,6 +2005,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/no_skip_for_integration_change.json b/recipe_modules/build/tests/full.expected/no_skip_for_integration_change.json
index 3cea724..ebb0147 100644
--- a/recipe_modules/build/tests/full.expected/no_skip_for_integration_change.json
+++ b/recipe_modules/build/tests/full.expected/no_skip_for_integration_change.json
@@ -2407,6 +2407,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/no_skip_if_recipe_testing_enabled.json b/recipe_modules/build/tests/full.expected/no_skip_if_recipe_testing_enabled.json
index 845ad36..b8dbddc 100644
--- a/recipe_modules/build/tests/full.expected/no_skip_if_recipe_testing_enabled.json
+++ b/recipe_modules/build/tests/full.expected/no_skip_if_recipe_testing_enabled.json
@@ -2407,6 +2407,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/size_creep_label_not_approved.json b/recipe_modules/build/tests/full.expected/size_creep_label_not_approved.json
index cc004ba..f310eca 100644
--- a/recipe_modules/build/tests/full.expected/size_creep_label_not_approved.json
+++ b/recipe_modules/build/tests/full.expected/size_creep_label_not_approved.json
@@ -3555,6 +3555,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/subbuild.json b/recipe_modules/build/tests/full.expected/subbuild.json
index 72087bb..6b35b37 100644
--- a/recipe_modules/build/tests/full.expected/subbuild.json
+++ b/recipe_modules/build/tests/full.expected/subbuild.json
@@ -3454,6 +3454,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.expected/upload_buildstats_failure.json b/recipe_modules/build/tests/full.expected/upload_buildstats_failure.json
index d9330fc..ec64792 100644
--- a/recipe_modules/build/tests/full.expected/upload_buildstats_failure.json
+++ b/recipe_modules/build/tests/full.expected/upload_buildstats_failure.json
@@ -3526,6 +3526,41 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/out/not-default/generated_sources.json",
       "/path/to/tmp/"
     ],
diff --git a/recipe_modules/build/tests/full.py b/recipe_modules/build/tests/full.py
index 19bb5e3..dff0402 100644
--- a/recipe_modules/build/tests/full.py
+++ b/recipe_modules/build/tests/full.py
@@ -98,6 +98,7 @@
     # These statements are just for test coverage, so don't lint them.
     # pylint: disable=pointless-statement
     build_results.boards
+    build_results.partitions
     build_results.compdb_path
     build_results.generated_sources
     build_results.gn_results.sdk_archives
diff --git a/recipes/fuchsia/build.expected/affected_tests_no_work.json b/recipes/fuchsia/build.expected/affected_tests_no_work.json
index a8684e2..7d955cd 100644
--- a/recipes/fuchsia/build.expected/affected_tests_no_work.json
+++ b/recipes/fuchsia/build.expected/affected_tests_no_work.json
@@ -46,7 +46,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
diff --git a/recipes/fuchsia/build.expected/catapult_dashboard_upload_enabled.json b/recipes/fuchsia/build.expected/catapult_dashboard_upload_enabled.json
index 8be2f03..f5c20ff 100644
--- a/recipes/fuchsia/build.expected/catapult_dashboard_upload_enabled.json
+++ b/recipes/fuchsia/build.expected/catapult_dashboard_upload_enabled.json
@@ -47,7 +47,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -4627,10 +4628,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/collect_absolute_coverage.json b/recipes/fuchsia/build.expected/collect_absolute_coverage.json
index c118cfc..2d990b2 100644
--- a/recipes/fuchsia/build.expected/collect_absolute_coverage.json
+++ b/recipes/fuchsia/build.expected/collect_absolute_coverage.json
@@ -47,7 +47,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -5090,10 +5091,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/collect_selective_coverage.json b/recipes/fuchsia/build.expected/collect_selective_coverage.json
index 25e90f5..2033940 100644
--- a/recipes/fuchsia/build.expected/collect_selective_coverage.json
+++ b/recipes/fuchsia/build.expected/collect_selective_coverage.json
@@ -47,7 +47,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -5092,10 +5093,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/cq_perfcompare.json b/recipes/fuchsia/build.expected/cq_perfcompare.json
index 1425d1b..ecdb3c4 100644
--- a/recipes/fuchsia/build.expected/cq_perfcompare.json
+++ b/recipes/fuchsia/build.expected/cq_perfcompare.json
@@ -47,7 +47,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -5116,10 +5117,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
@@ -8998,11 +9075,87 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "build without CL.publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "build without CL.publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "build without CL.publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "build without CL.set cas_digests output property",
     "~followup_annotations": [
       "@@@STEP_NEST_LEVEL@1@@@",
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/default.json b/recipes/fuchsia/build.expected/default.json
index ac99972..4f313a7 100644
--- a/recipes/fuchsia/build.expected/default.json
+++ b/recipes/fuchsia/build.expected/default.json
@@ -45,7 +45,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -3483,10 +3484,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/default_cq.json b/recipes/fuchsia/build.expected/default_cq.json
index d733d88..aef2bb6 100644
--- a/recipes/fuchsia/build.expected/default_cq.json
+++ b/recipes/fuchsia/build.expected/default_cq.json
@@ -50,7 +50,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -5101,10 +5102,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/default_cq_no_affected_retry_task_on_test_failure.json b/recipes/fuchsia/build.expected/default_cq_no_affected_retry_task_on_test_failure.json
index d964245..bb1163d 100644
--- a/recipes/fuchsia/build.expected/default_cq_no_affected_retry_task_on_test_failure.json
+++ b/recipes/fuchsia/build.expected/default_cq_no_affected_retry_task_on_test_failure.json
@@ -47,7 +47,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -5094,10 +5095,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/default_multipliers.json b/recipes/fuchsia/build.expected/default_multipliers.json
index c72112f..b03ba99 100644
--- a/recipes/fuchsia/build.expected/default_multipliers.json
+++ b/recipes/fuchsia/build.expected/default_multipliers.json
@@ -44,7 +44,8 @@
       "@@@STEP_LOG_LINE@properties@      \"enable_sandboxing\": true@@@",
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -5168,10 +5169,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "integration:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "integration:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/failed_build_cq.json b/recipes/fuchsia/build.expected/failed_build_cq.json
index 2de9fc2..c3e6baf 100644
--- a/recipes/fuchsia/build.expected/failed_build_cq.json
+++ b/recipes/fuchsia/build.expected/failed_build_cq.json
@@ -30,7 +30,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$fuchsia/autocorrelator\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"ci_bucket\": \"ci\",@@@",
diff --git a/recipes/fuchsia/build.expected/failed_build_cq_no_rebase.json b/recipes/fuchsia/build.expected/failed_build_cq_no_rebase.json
index dbf8311..2554103 100644
--- a/recipes/fuchsia/build.expected/failed_build_cq_no_rebase.json
+++ b/recipes/fuchsia/build.expected/failed_build_cq_no_rebase.json
@@ -30,7 +30,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
diff --git a/recipes/fuchsia/build.expected/non_numeric_parent_id.json b/recipes/fuchsia/build.expected/non_numeric_parent_id.json
index 4be413e..7b22e38 100644
--- a/recipes/fuchsia/build.expected/non_numeric_parent_id.json
+++ b/recipes/fuchsia/build.expected/non_numeric_parent_id.json
@@ -45,7 +45,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -4625,10 +4626,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/run_all_tests.json b/recipes/fuchsia/build.expected/run_all_tests.json
index 6ff6489..aa3e1e5 100644
--- a/recipes/fuchsia/build.expected/run_all_tests.json
+++ b/recipes/fuchsia/build.expected/run_all_tests.json
@@ -43,7 +43,8 @@
       "@@@STEP_LOG_LINE@properties@      \"enable_sandboxing\": true@@@",
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -4014,10 +4015,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "integration:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "integration:try"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.expected/sdk.json b/recipes/fuchsia/build.expected/sdk.json
index 2d6af28..12e03f5 100644
--- a/recipes/fuchsia/build.expected/sdk.json
+++ b/recipes/fuchsia/build.expected/sdk.json
@@ -34,7 +34,8 @@
       "@@@STEP_LOG_LINE@properties@      \"enable_sandboxing\": true@@@",
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -4856,6 +4857,251 @@
       "--json-output",
       "/path/to/tmp/json",
       "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "ls-remote",
+      "--heads",
+      "https://fuchsia.googlesource.com/manifest",
+      "refs/heads/releases/canary"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.git ls-remote",
+    "timeout": 600.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LOG_LINE@stdout@h3ll0\trefs/heads/refs/heads/releases/canary@@@",
+      "@@@STEP_LOG_END@stdout@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "fetch",
+      "--jobs",
+      "4",
+      "origin",
+      "h3ll0"
+    ],
+    "cwd": "[START_DIR]/fuchsia/integration",
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.git fetch",
+    "timeout": 1200.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "git",
+      "--no-pager",
+      "tag",
+      "--merged",
+      "h3ll0"
+    ],
+    "cwd": "[START_DIR]/fuchsia/integration",
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.get release versions on h3ll0",
+    "timeout": 600.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.cipd",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@SET_BUILD_PROPERTY@git_revision@\"a491082dc1b632bbcd60ba3618d20b503c2de738\"@@@",
+      "@@@SET_BUILD_PROPERTY@instance_id@\"40-chars-fake-of-the-package-instance_id\"@@@",
+      "@@@SET_BUILD_PROPERTY@package@\"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\"@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "pkg-build",
+      "-pkg-def",
+      "{\"data\": [{\"dir\": \".\", \"exclude\": []}, {\"version_file\": \".versions/obj.cipd_version\"}], \"install_mode\": \"copy\", \"package\": \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \"root\": \"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\"}",
+      "-out",
+      "[CLEANUP]/cipd-util-build_tmp_3/obj.pkg",
+      "-hash-algo",
+      "sha256",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.cipd.build fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"instance_id\": \"40-chars-fake-of-the-package-instance_id\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"package\": \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "search",
+      "fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition",
+      "-tag",
+      "git_revision:a491082dc1b632bbcd60ba3618d20b503c2de738",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.cipd.cipd search fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition git_revision:a491082dc1b632bbcd60ba3618d20b503c2de738",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": []@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "cipd",
+      "pkg-register",
+      "[CLEANUP]/cipd-util-build_tmp_3/obj.pkg",
+      "-tag",
+      "git_revision:a491082dc1b632bbcd60ba3618d20b503c2de738",
+      "-tag",
+      "version:0.20191018.0.1",
+      "-metadata",
+      "bbid:8945511751514863184",
+      "-metadata",
+      "version:0.20191018.0.1",
+      "-json-output",
+      "/path/to/tmp/json"
+    ],
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.cipd.register fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@3@@@",
+      "@@@STEP_LOG_LINE@json.output@{@@@",
+      "@@@STEP_LOG_LINE@json.output@  \"result\": {@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"instance_id\": \"40-chars-fake-of-the-package-instance_id\",@@@",
+      "@@@STEP_LOG_LINE@json.output@    \"package\": \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@json.output@  }@@@",
+      "@@@STEP_LOG_LINE@json.output@}@@@",
+      "@@@STEP_LOG_END@json.output@@@",
+      "@@@STEP_LINK@fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition@https://chrome-infra-packages.appspot.com/p/fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition/+/40-chars-fake-of-the-package-instance_id@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
       "[START_DIR]/fuchsia/out/not-default/sdk_archives.json",
       "/path/to/tmp/"
     ],
diff --git a/recipes/fuchsia/build.expected/skip_if_unaffected.json b/recipes/fuchsia/build.expected/skip_if_unaffected.json
index f47a649..7f01963 100644
--- a/recipes/fuchsia/build.expected/skip_if_unaffected.json
+++ b/recipes/fuchsia/build.expected/skip_if_unaffected.json
@@ -46,7 +46,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
diff --git a/recipes/fuchsia/build.expected/subbuild_no_parent_id.json b/recipes/fuchsia/build.expected/subbuild_no_parent_id.json
index 4d41dd1..bc69017 100644
--- a/recipes/fuchsia/build.expected/subbuild_no_parent_id.json
+++ b/recipes/fuchsia/build.expected/subbuild_no_parent_id.json
@@ -36,7 +36,8 @@
       "@@@STEP_LOG_LINE@properties@      \"enable_sandboxing\": true@@@",
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
diff --git a/recipes/fuchsia/build.expected/test_on_gce.json b/recipes/fuchsia/build.expected/test_on_gce.json
index f57b79f..29dfedd 100644
--- a/recipes/fuchsia/build.expected/test_on_gce.json
+++ b/recipes/fuchsia/build.expected/test_on_gce.json
@@ -50,7 +50,8 @@
       "@@@STEP_LOG_LINE@properties@    },@@@",
       "@@@STEP_LOG_LINE@properties@    \"gcs_bucket\": \"fuchsia-infra\",@@@",
       "@@@STEP_LOG_LINE@properties@    \"artifact_gcs_bucket\": \"fuchsia-infra-artifacts\",@@@",
-      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\"@@@",
+      "@@@STEP_LOG_LINE@properties@    \"board_cipd_prefix\": \"fuchsia/assembly/boards\",@@@",
+      "@@@STEP_LOG_LINE@properties@    \"partitions_cipd_prefix\": \"fuchsia/assembly/partitions\"@@@",
       "@@@STEP_LOG_LINE@properties@  },@@@",
       "@@@STEP_LOG_LINE@properties@  \"$recipe_engine/buildbucket\": {@@@",
       "@@@STEP_LOG_LINE@properties@    \"build\": {@@@",
@@ -4630,10 +4631,86 @@
     ]
   },
   {
+    "cmd": [
+      "vpython3",
+      "-u",
+      "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+      "--json-output",
+      "/path/to/tmp/json",
+      "copy",
+      "[START_DIR]/fuchsia/out/not-default/partitions.json",
+      "/path/to/tmp/"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.read partitions.json",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@",
+      "@@@STEP_LOG_LINE@partitions.json@[@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  {@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"name\": \"foo\",@@@",
+      "@@@STEP_LOG_LINE@partitions.json@    \"outdir\": \"obj/foo-partition\"@@@",
+      "@@@STEP_LOG_LINE@partitions.json@  }@@@",
+      "@@@STEP_LOG_LINE@partitions.json@]@@@",
+      "@@@STEP_LOG_END@partitions.json@@@"
+    ]
+  },
+  {
+    "cmd": [],
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo",
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@1@@@"
+    ]
+  },
+  {
+    "cmd": [
+      "[START_DIR]/cipd_tool/infra/tools/luci/cas/33f9d887e5b8aeaaf9d65506acccfa8da2c480712e534a23a79e92c342c44bee/cas",
+      "archive",
+      "-log-level",
+      "debug",
+      "-cas-instance",
+      "projects/example-cas-server/instances/default_instance",
+      "-dump-digest",
+      "/path/to/tmp/",
+      "-paths-json",
+      "[[\"[START_DIR]/fuchsia/out/not-default/obj/foo-partition\", \".\"]]"
+    ],
+    "infra_step": true,
+    "luci_context": {
+      "realm": {
+        "name": "fuchsia:ci"
+      },
+      "resultdb": {
+        "current_invocation": {
+          "name": "invocations/build:8945511751514863184",
+          "update_token": "token"
+        },
+        "hostname": "rdbhost"
+      }
+    },
+    "name": "publish assembly artifacts.publish partitions to CIPD: foo.archive",
+    "timeout": 900.0,
+    "~followup_annotations": [
+      "@@@STEP_NEST_LEVEL@2@@@",
+      "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+    ]
+  },
+  {
     "cmd": [],
     "name": "set cas_digests output property",
     "~followup_annotations": [
-      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
+      "@@@SET_BUILD_PROPERTY@cas_digests@{\"fuchsia/assembly-inputs/core.x64\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/boards/foo\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\", \"fuchsia/assembly/partitions/[START_DIR]/fuchsia/out/not-default/obj/foo-partition\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"}@@@"
     ]
   },
   {
diff --git a/recipes/fuchsia/build.py b/recipes/fuchsia/build.py
index b312f78..3836be4 100644
--- a/recipes/fuchsia/build.py
+++ b/recipes/fuchsia/build.py
@@ -293,6 +293,21 @@
                         cas_digests,
                     )
 
+        if spec.partitions_cipd_prefix:
+            for partitions_name, partitions_path in build_results.partitions.items():
+                with api.step.nest(
+                    f"publish partitions to CIPD: {partitions_name}"
+                ) as presentation:
+                    publish_tree(
+                        api,
+                        checkout,
+                        spec,
+                        "%s/%s"
+                        % (spec.partitions_cipd_prefix.rstrip("/"), partitions_path),
+                        partitions_path,
+                        cas_digests,
+                    )
+
     if cas_digests:
         with api.step.nest("set cas_digests output property") as presentation:
             presentation.properties["cas_digests"] = cas_digests
@@ -674,6 +689,7 @@
                 gcs_bucket=gcs_bucket,
                 artifact_gcs_bucket="fuchsia-infra-artifacts",
                 board_cipd_prefix="fuchsia/assembly/boards",
+                partitions_cipd_prefix="fuchsia/assembly/partitions",
             ),
             **kwargs,
         )
diff --git a/recipes/fuchsia/spec.proto b/recipes/fuchsia/spec.proto
index cfab37a..b4cc57e 100644
--- a/recipes/fuchsia/spec.proto
+++ b/recipes/fuchsia/spec.proto
@@ -38,6 +38,11 @@
   // `boards.json` build API module. No upload will happen if this is empty.
   string board_cipd_prefix = 6;
 
+  // The CIPD package base prefix to release all partition configs specified in
+  // the `partitions.json` build API module.
+  // No upload will happen if this is empty.
+  string partitions_cipd_prefix = 7;
+
   // Describes how to fetch the Fuchsia build inputs.
   message Checkout {
     // Jiri <package> attribute values indicating additional packages to fetch