prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [Bug]: The location specified in bundle-manifest (manifest.yml) are invalid
  ### Describe the bug
  
  A build manifest is bundled inside the OpenSearch bundle tarball (manifest.yml) which contains all the information about the components used to build the bundle. The bundle manifest contains a key `location` whose value is invalid for all components.
  
  ```
  build:
    architecture: x64
    id: '317'
    location: https://ci.opensearch.org/ci/bundles/1.1.0/317/opensearch-1.1.0-linux-x64.tar.gz
    name: OpenSearch
    version: 1.1.0
  components:
  - commit_id: 15e9f137622d878b79103df8f82d78d782b686a1
    location: https://ci.opensearch.org/ci/builds/1.1.0/317/bundle/opensearch-min-1.1.0-linux-x64.tar.gz
    name: OpenSearch
    ref: '1.1'
    repository: https://github.com/opensearch-project/OpenSearch.git
  ```
  
  ### To reproduce
  
  Download the bundle. Untar it and see the manifest.yml
  
  Try accessing the location url to download individual component. It will give `Access Denied` error
  
  ### Expected behavior
  
  The URLs should be valid. Each component should be downloadable from the given location url
  
  ### Screenshots
  
  _No response_
  
  ### Host / Environment
  
  _No response_
  
  ### Additional context
  
  _No response_
  
  ### Relevant log output
  
  _No response_
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `bundle-workflow/src/assemble_workflow/bundle_recorder.py`
  Content:
  ```
  1 # SPDX-License-Identifier: Apache-2.0
  2 #
  3 # The OpenSearch Contributors require contributions made to
  4 # this file be licensed under the Apache-2.0 license or a
  5 # compatible open source license.
  6 
  7 import os
  8 from urllib.parse import urljoin
  9 
  10 from manifests.bundle_manifest import BundleManifest
  11 
  12 
  13 class BundleRecorder:
  14     def __init__(self, build, output_dir, artifacts_dir):
  15         self.output_dir = output_dir
  16         self.build_id = build.id
  17         self.public_url = os.getenv("PUBLIC_ARTIFACT_URL", None)
  18         self.version = build.version
  19         self.tar_name = self.__get_tar_name(build)
  20         self.artifacts_dir = artifacts_dir
  21         self.bundle_manifest = self.BundleManifestBuilder(
  22             build.id,
  23             build.name,
  24             build.version,
  25             build.architecture,
  26             self.__get_tar_location(),
  27         )
  28 
  29     def __get_tar_name(self, build):
  30         parts = [build.name.lower(), build.version, "linux", build.architecture]
  31         return "-".join(parts) + ".tar.gz"
  32 
  33     def __get_public_url_path(self, folder, rel_path):
  34         path = "{}/{}/{}/{}".format(folder, self.version, self.build_id, rel_path)
  35         return urljoin(self.public_url, path)
  36 
  37     def __get_location(self, folder_name, rel_path, abs_path):
  38         if self.public_url:
  39             return self.__get_public_url_path(folder_name, rel_path)
  40         return abs_path
  41 
  42     # Assembled bundles are expected to be served from a separate "bundles" folder
  43     # Example: https://artifacts.opensearch.org/bundles/1.0.0/<build-id
  44     def __get_tar_location(self):
  45         return self.__get_location(
  46             "bundles", self.tar_name, os.path.join(self.output_dir, self.tar_name)
  47         )
  48 
  49     # Build artifacts are expected to be served from a "builds" folder
  50     # Example: https://artifacts.opensearch.org/builds/1.0.0/<build-id>
  51     def __get_component_location(self, component_rel_path):
  52         abs_path = os.path.join(self.artifacts_dir, component_rel_path)
  53         return self.__get_location("builds", component_rel_path, abs_path)
  54 
  55     def record_component(self, component, rel_path):
  56         self.bundle_manifest.append_component(
  57             component.name,
  58             component.repository,
  59             component.ref,
  60             component.commit_id,
  61             self.__get_component_location(rel_path),
  62         )
  63 
  64     def get_manifest(self):
  65         return self.bundle_manifest.to_manifest()
  66 
  67     def write_manifest(self, folder):
  68         manifest_path = os.path.join(folder, "manifest.yml")
  69         self.get_manifest().to_file(manifest_path)
  70 
  71     class BundleManifestBuilder:
  72         def __init__(self, build_id, name, version, arch, location):
  73             self.data = {}
  74             self.data["build"] = {}
  75             self.data["build"]["id"] = build_id
  76             self.data["build"]["name"] = name
  77             self.data["build"]["version"] = str(version)
  78             self.data["build"]["architecture"] = arch
  79             self.data["build"]["location"] = location
  80             self.data["schema-version"] = "1.0"
  81             # We need to store components as a hash so that we can append artifacts by component name
  82             # When we convert to a BundleManifest this will get converted back into a list
  83             self.data["components"] = []
  84 
  85         def append_component(self, name, repository_url, ref, commit_id, location):
  86             component = {
  87                 "name": name,
  88                 "repository": repository_url,
  89                 "ref": ref,
  90                 "commit_id": commit_id,
  91                 "location": location,
  92             }
  93             self.data["components"].append(component)
  94 
  95         def to_manifest(self):
  96             return BundleManifest(self.data)
  97
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/bundle-workflow/src/assemble_workflow/bundle_recorder.py b/bundle-workflow/src/assemble_workflow/bundle_recorder.py
  --- a/bundle-workflow/src/assemble_workflow/bundle_recorder.py
  +++ b/bundle-workflow/src/assemble_workflow/bundle_recorder.py
  @@ -31,8 +31,8 @@
           return "-".join(parts) + ".tar.gz"
   
       def __get_public_url_path(self, folder, rel_path):
  -        path = "{}/{}/{}/{}".format(folder, self.version, self.build_id, rel_path)
  -        return urljoin(self.public_url, path)
  +        path = "/".join((folder, self.version, self.build_id, rel_path))
  +        return urljoin(self.public_url + "/", path)
   
       def __get_location(self, folder_name, rel_path, abs_path):
           if self.public_url:
  
verification_info: {"golden_diff": "diff --git a/bundle-workflow/src/assemble_workflow/bundle_recorder.py b/bundle-workflow/src/assemble_workflow/bundle_recorder.py\n--- a/bundle-workflow/src/assemble_workflow/bundle_recorder.py\n+++ b/bundle-workflow/src/assemble_workflow/bundle_recorder.py\n@@ -31,8 +31,8 @@\n         return \"-\".join(parts) + \".tar.gz\"\n \n     def __get_public_url_path(self, folder, rel_path):\n-        path = \"{}/{}/{}/{}\".format(folder, self.version, self.build_id, rel_path)\n-        return urljoin(self.public_url, path)\n+        path = \"/\".join((folder, self.version, self.build_id, rel_path))\n+        return urljoin(self.public_url + \"/\", path)\n \n     def __get_location(self, folder_name, rel_path, abs_path):\n         if self.public_url:\n", "issue": "[Bug]: The location specified in bundle-manifest (manifest.yml) are invalid\n### Describe the bug\n\nA build manifest is bundled inside the OpenSearch bundle tarball (manifest.yml) which contains all the information about the components used to build the bundle. The bundle manifest contains a key `location` whose value is invalid for all components.\r\n\r\n```\r\nbuild:\r\n  architecture: x64\r\n  id: '317'\r\n  location: https://ci.opensearch.org/ci/bundles/1.1.0/317/opensearch-1.1.0-linux-x64.tar.gz\r\n  name: OpenSearch\r\n  version: 1.1.0\r\ncomponents:\r\n- commit_id: 15e9f137622d878b79103df8f82d78d782b686a1\r\n  location: https://ci.opensearch.org/ci/builds/1.1.0/317/bundle/opensearch-min-1.1.0-linux-x64.tar.gz\r\n  name: OpenSearch\r\n  ref: '1.1'\r\n  repository: https://github.com/opensearch-project/OpenSearch.git\r\n```\n\n### To reproduce\n\nDownload the bundle. Untar it and see the manifest.yml\r\n\r\nTry accessing the location url to download individual component. It will give `Access Denied` error\n\n### Expected behavior\n\nThe URLs should be valid. Each component should be downloadable from the given location url\n\n### Screenshots\n\n_No response_\n\n### Host / Environment\n\n_No response_\n\n### Additional context\n\n_No response_\n\n### Relevant log output\n\n_No response_\n", "before_files": [{"content": "# SPDX-License-Identifier: Apache-2.0\n#\n# The OpenSearch Contributors require contributions made to\n# this file be licensed under the Apache-2.0 license or a\n# compatible open source license.\n\nimport os\nfrom urllib.parse import urljoin\n\nfrom manifests.bundle_manifest import BundleManifest\n\n\nclass BundleRecorder:\n    def __init__(self, build, output_dir, artifacts_dir):\n        self.output_dir = output_dir\n        self.build_id = build.id\n        self.public_url = os.getenv(\"PUBLIC_ARTIFACT_URL\", None)\n        self.version = build.version\n        self.tar_name = self.__get_tar_name(build)\n        self.artifacts_dir = artifacts_dir\n        self.bundle_manifest = self.BundleManifestBuilder(\n            build.id,\n            build.name,\n            build.version,\n            build.architecture,\n            self.__get_tar_location(),\n        )\n\n    def __get_tar_name(self, build):\n        parts = [build.name.lower(), build.version, \"linux\", build.architecture]\n        return \"-\".join(parts) + \".tar.gz\"\n\n    def __get_public_url_path(self, folder, rel_path):\n        path = \"{}/{}/{}/{}\".format(folder, self.version, self.build_id, rel_path)\n        return urljoin(self.public_url, path)\n\n    def __get_location(self, folder_name, rel_path, abs_path):\n        if self.public_url:\n            return self.__get_public_url_path(folder_name, rel_path)\n        return abs_path\n\n    # Assembled bundles are expected to be served from a separate \"bundles\" folder\n    # Example: https://artifacts.opensearch.org/bundles/1.0.0/<build-id\n    def __get_tar_location(self):\n        return self.__get_location(\n            \"bundles\", self.tar_name, os.path.join(self.output_dir, self.tar_name)\n        )\n\n    # Build artifacts are expected to be served from a \"builds\" folder\n    # Example: https://artifacts.opensearch.org/builds/1.0.0/<build-id>\n    def __get_component_location(self, component_rel_path):\n        abs_path = os.path.join(self.artifacts_dir, component_rel_path)\n        return self.__get_location(\"builds\", component_rel_path, abs_path)\n\n    def record_component(self, component, rel_path):\n        self.bundle_manifest.append_component(\n            component.name,\n            component.repository,\n            component.ref,\n            component.commit_id,\n            self.__get_component_location(rel_path),\n        )\n\n    def get_manifest(self):\n        return self.bundle_manifest.to_manifest()\n\n    def write_manifest(self, folder):\n        manifest_path = os.path.join(folder, \"manifest.yml\")\n        self.get_manifest().to_file(manifest_path)\n\n    class BundleManifestBuilder:\n        def __init__(self, build_id, name, version, arch, location):\n            self.data = {}\n            self.data[\"build\"] = {}\n            self.data[\"build\"][\"id\"] = build_id\n            self.data[\"build\"][\"name\"] = name\n            self.data[\"build\"][\"version\"] = str(version)\n            self.data[\"build\"][\"architecture\"] = arch\n            self.data[\"build\"][\"location\"] = location\n            self.data[\"schema-version\"] = \"1.0\"\n            # We need to store components as a hash so that we can append artifacts by component name\n            # When we convert to a BundleManifest this will get converted back into a list\n            self.data[\"components\"] = []\n\n        def append_component(self, name, repository_url, ref, commit_id, location):\n            component = {\n                \"name\": name,\n                \"repository\": repository_url,\n                \"ref\": ref,\n                \"commit_id\": commit_id,\n                \"location\": location,\n            }\n            self.data[\"components\"].append(component)\n\n        def to_manifest(self):\n            return BundleManifest(self.data)\n", "path": "bundle-workflow/src/assemble_workflow/bundle_recorder.py"}], "after_files": [{"content": "# SPDX-License-Identifier: Apache-2.0\n#\n# The OpenSearch Contributors require contributions made to\n# this file be licensed under the Apache-2.0 license or a\n# compatible open source license.\n\nimport os\nfrom urllib.parse import urljoin\n\nfrom manifests.bundle_manifest import BundleManifest\n\n\nclass BundleRecorder:\n    def __init__(self, build, output_dir, artifacts_dir):\n        self.output_dir = output_dir\n        self.build_id = build.id\n        self.public_url = os.getenv(\"PUBLIC_ARTIFACT_URL\", None)\n        self.version = build.version\n        self.tar_name = self.__get_tar_name(build)\n        self.artifacts_dir = artifacts_dir\n        self.bundle_manifest = self.BundleManifestBuilder(\n            build.id,\n            build.name,\n            build.version,\n            build.architecture,\n            self.__get_tar_location(),\n        )\n\n    def __get_tar_name(self, build):\n        parts = [build.name.lower(), build.version, \"linux\", build.architecture]\n        return \"-\".join(parts) + \".tar.gz\"\n\n    def __get_public_url_path(self, folder, rel_path):\n        path = \"/\".join((folder, self.version, self.build_id, rel_path))\n        return urljoin(self.public_url + \"/\", path)\n\n    def __get_location(self, folder_name, rel_path, abs_path):\n        if self.public_url:\n            return self.__get_public_url_path(folder_name, rel_path)\n        return abs_path\n\n    # Assembled bundles are expected to be served from a separate \"bundles\" folder\n    # Example: https://artifacts.opensearch.org/bundles/1.0.0/<build-id\n    def __get_tar_location(self):\n        return self.__get_location(\n            \"bundles\", self.tar_name, os.path.join(self.output_dir, self.tar_name)\n        )\n\n    # Build artifacts are expected to be served from a \"builds\" folder\n    # Example: https://artifacts.opensearch.org/builds/1.0.0/<build-id>\n    def __get_component_location(self, component_rel_path):\n        abs_path = os.path.join(self.artifacts_dir, component_rel_path)\n        return self.__get_location(\"builds\", component_rel_path, abs_path)\n\n    def record_component(self, component, rel_path):\n        self.bundle_manifest.append_component(\n            component.name,\n            component.repository,\n            component.ref,\n            component.commit_id,\n            self.__get_component_location(rel_path),\n        )\n\n    def get_manifest(self):\n        return self.bundle_manifest.to_manifest()\n\n    def write_manifest(self, folder):\n        manifest_path = os.path.join(folder, \"manifest.yml\")\n        self.get_manifest().to_file(manifest_path)\n\n    class BundleManifestBuilder:\n        def __init__(self, build_id, name, version, arch, location):\n            self.data = {}\n            self.data[\"build\"] = {}\n            self.data[\"build\"][\"id\"] = build_id\n            self.data[\"build\"][\"name\"] = name\n            self.data[\"build\"][\"version\"] = str(version)\n            self.data[\"build\"][\"architecture\"] = arch\n            self.data[\"build\"][\"location\"] = location\n            self.data[\"schema-version\"] = \"1.0\"\n            # We need to store components as a hash so that we can append artifacts by component name\n            # When we convert to a BundleManifest this will get converted back into a list\n            self.data[\"components\"] = []\n\n        def append_component(self, name, repository_url, ref, commit_id, location):\n            component = {\n                \"name\": name,\n                \"repository\": repository_url,\n                \"ref\": ref,\n                \"commit_id\": commit_id,\n                \"location\": location,\n            }\n            self.data[\"components\"].append(component)\n\n        def to_manifest(self):\n            return BundleManifest(self.data)\n", "path": "bundle-workflow/src/assemble_workflow/bundle_recorder.py"}]}