From f4d2566642a84c423fbc5d1667d43f30215e1c59 Mon Sep 17 00:00:00 2001
From: Natalie Gaston <natalie.gaston@intel.com>
Date: Wed, 10 Jan 2024 15:47:55 -0800
Subject: [PATCH] Implement using deb822 format in source application add
 command (#457)

---
 docs/Manifest Parameters.md                   | 121 ++++++++++++++----
 inbc-program/README.md                        |  78 +++++++++--
 inbc-program/inbc/parser/parser.py            |   6 +-
 inbc-program/inbc/parser/source_app_parser.py |  40 ++++--
 .../tests/unit/test_source_app_parser.py      | 110 +++++++++++++++-
 .../dispatcher/source/constants.py            |   7 +-
 .../dispatcher/source/source_command.py       |  24 +++-
 .../source/ubuntu_source_manager.py           |  15 ++-
 .../dispatcher-agent/manifest_schema.xsd      |  14 +-
 .../unit/source/test_ubuntu_source_cmd.py     |  37 +++++-
 inbm/integration-reloaded/README.md           |  18 +--
 .../test/source/SOURCE.sh                     |  15 +++
 12 files changed, 391 insertions(+), 94 deletions(-)

diff --git a/docs/Manifest Parameters.md b/docs/Manifest Parameters.md
index 266a689f1..31b9efe74 100644
--- a/docs/Manifest Parameters.md	
+++ b/docs/Manifest Parameters.md	
@@ -918,10 +918,10 @@ The query command can be used to gather information about the system and the Vis
 | `<type></type>`                          | `<type>source</type>`                                                                          |         R         |                 |
 | `<applicationSource>`                    | `<applicationSource>`                                                                          |         R         |                 |
 | `<add>`                                  | `<add>`                                                                                        |         R         |                 |
-| `<gpg>`                                  | `<gpg>`                                                                                        |         R         |                 |
-| `<uri></uri>`                            | `<uri>https://dl-ssl.google.com/linux/linux_signing_key.pub</uri>`                             |         R         |                 |
-| `<keyname></keyname>`                    | `<keyname>google-chrome.gpg</keyname>`                                                         |         R         |                 | 
-| `</gpg>`                                 | `</gpg>`                                                                                       |         R         |                 |
+| `<gpg>`                                  | `<gpg>`                                                                                        |         O         |                 |
+| `<uri></uri>`                            | `<uri>https://dl-ssl.google.com/linux/linux_signing_key.pub</uri>`                             |         O         |                 |
+| `<keyname></keyname>`                    | `<keyname>google-chrome.gpg</keyname>`                                                         |         O         |                 | 
+| `</gpg>`                                 | `</gpg>`                                                                                       |         O         |                 |
 | `<repo>`                                 | `<repo>`                                                                                       |         R         |                 |
 | `<repos>`                                | `<repos>`                                                                                      |         R         |                 |
 | `<source_pkg>`                           | `<source_pkg>deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main</source_pkg>` |         R         |                 |
@@ -935,7 +935,7 @@ The query command can be used to gather information about the system and the Vis
 
 
 
-#### Source application add Manifest Example
+#### Source Application Add Manifest Example using remote GPG key
 ```xml
 <?xml version="1.0" encoding="UTF-8"?>
 <manifest>
@@ -958,6 +958,59 @@ The query command can be used to gather information about the system and the Vis
 </manifest>
 ```
 
+#### Source Application Add Manifest Example (deb822 format)
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest>
+    <type>source</type>
+    <applicationSource>
+            <repo>
+                <repos>
+                    <source_pkg>Enabled: yes</source_pkg>
+                    <source_pkg>Types: deb</source_pkg>
+                    <source_pkg>URIs: http://dl.google.com/linux/chrome/deb/</source_pkg>
+                    <source_pkg>Suites: stable</source_pkg>
+                    <source_pkg>Components: main</source_pkg>
+                    <source_pkg>Signed-By:</source_pkg>
+                    <source_pkg> -----BEGIN PGP PUBLIC KEY BLOCK-----</source_pkg>
+                    <source_pkg> Version: GnuPG v1.4.2.2 (GNU/Linux)</source_pkg>
+                    <source_pkg> .</source_pkg>
+                    <source_pkg> mQGiBEXwb0YRBADQva2NLpYXxgjNkbuP0LnPoEXruGmvi3XMIxjEUFuGNCP4Rj/a</source_pkg>
+                    <source_pkg> kv2E5VixBP1vcQFDRJ+p1puh8NU0XERlhpyZrVMzzS/RdWdyXf7E5S8oqNXsoD1z</source_pkg>
+                    <source_pkg> fvmI+i9b2EhHAA19Kgw7ifV8vMa4tkwslEmcTiwiw8lyUl28Wh4Et8SxzwCggDcA</source_pkg>
+                    <source_pkg> feGqtn3PP5YAdD0km4S4XeMEAJjlrqPoPv2Gf//tfznY2UyS9PUqFCPLHgFLe80u</source_pkg>
+                    <source_pkg> QhI2U5jt6jUKN4fHauvR6z3seSAsh1YyzyZCKxJFEKXCCqnrFSoh4WSJsbFNc4PN</source_pkg>
+                    <source_pkg> b0V0SqiTCkWADZyLT5wll8sWuQ5ylTf3z1ENoHf+G3um3/wk/+xmEHvj9HCTBEXP</source_pkg>
+                    <source_pkg> 78X0A/0Tqlhc2RBnEf+AqxWvM8sk8LzJI/XGjwBvKfXe+l3rnSR2kEAvGzj5Sg0X</source_pkg>
+                    <source_pkg> 4XmfTg4Jl8BNjWyvm2Wmjfet41LPmYJKsux3g0b8yzQxeOA4pQKKAU3Z4+rgzGmf</source_pkg>
+                    <source_pkg> HdwCG5MNT2A5XxD/eDd+L4fRx0HbFkIQoAi1J3YWQSiTk15fw7RMR29vZ2xlLCBJ</source_pkg>
+                    <source_pkg> bmMuIExpbnV4IFBhY2thZ2UgU2lnbmluZyBLZXkgPGxpbnV4LXBhY2thZ2VzLWtl</source_pkg>
+                    <source_pkg> eW1hc3RlckBnb29nbGUuY29tPohjBBMRAgAjAhsDBgsJCAcDAgQVAggDBBYCAwEC</source_pkg>
+                    <source_pkg> HgECF4AFAkYVdn8CGQEACgkQoECDD3+sWZHKSgCfdq3HtNYJLv+XZleb6HN4zOcF</source_pkg>
+                    <source_pkg> AJEAniSFbuv8V5FSHxeRimHx25671az+uQINBEXwb0sQCACuA8HT2nr+FM5y/kzI</source_pkg>
+                    <source_pkg> A51ZcC46KFtIDgjQJ31Q3OrkYP8LbxOpKMRIzvOZrsjOlFmDVqitiVc7qj3lYp6U</source_pkg>
+                    <source_pkg> rgNVaFv6Qu4bo2/ctjNHDDBdv6nufmusJUWq/9TwieepM/cwnXd+HMxu1XBKRVk9</source_pkg>
+                    <source_pkg> XyAZ9SvfcW4EtxVgysI+XlptKFa5JCqFM3qJllVohMmr7lMwO8+sxTWTXqxsptJo</source_pkg>
+                    <source_pkg> pZeKz+UBEEqPyw7CUIVYGC9ENEtIMFvAvPqnhj1GS96REMpry+5s9WKuLEaclWpd</source_pkg>
+                    <source_pkg> K3krttbDlY1NaeQUCRvBYZ8iAG9YSLHUHMTuI2oea07Rh4dtIAqPwAX8xn36JAYG</source_pkg>
+                    <source_pkg> 2vgLAAMFB/wKqaycjWAZwIe98Yt0qHsdkpmIbarD9fGiA6kfkK/UxjL/k7tmS4Vm</source_pkg>
+                    <source_pkg> CljrrDZkPSQ/19mpdRcGXtb0NI9+nyM5trweTvtPw+HPkDiJlTaiCcx+izg79Fj9</source_pkg>
+                    <source_pkg> KcofuNb3lPdXZb9tzf5oDnmm/B+4vkeTuEZJ//IFty8cmvCpzvY+DAz1Vo9rA+Zn</source_pkg>
+                    <source_pkg> cpWY1n6z6oSS9AsyT/IFlWWBZZ17SpMHu+h4Bxy62+AbPHKGSujEGQhWq8ZRoJAT</source_pkg>
+                    <source_pkg> G0KSObnmZ7FwFWu1e9XFoUCt0bSjiJWTIyaObMrWu/LvJ3e9I87HseSJStfw6fki</source_pkg>
+                    <source_pkg> 5og9qFEkMrIrBCp3QGuQWBq/rTdMuwNFiEkEGBECAAkFAkXwb0sCGwwACgkQoECD</source_pkg>
+                    <source_pkg> D3+sWZF/WACfeNAu1/1hwZtUo1bR+MWiCjpvHtwAnA1R3IHqFLQ2X3xJ40XPuAyY</source_pkg>
+                    <source_pkg> /FJG</source_pkg>
+                    <source_pkg> %20=Quqp</source_pkg>
+                    <source_pkg> -----END PGP PUBLIC KEY BLOCK-----</source_pkg>
+                </repos>
+                <filename>google-chrome.sources</filename>
+            </repo>
+        </add>
+    </applicationSource>
+</manifest>
+```
+
 #### Source Application Update Manifest Parameters
 | Tag                                      | Example                                                                                        | Required/Optional | Notes |
 |:-----------------------------------------|:-----------------------------------------------------------------------------------------------|:-----------------:|:------|
@@ -966,7 +1019,6 @@ The query command can be used to gather information about the system and the Vis
 | `<type></type>`                          | `<type>source</type>`                                                                          |         R         |       |
 | `<applicationSource>`                    | `<applicationSource>`                                                                          |         R         |       |
 | `<update>`                               | `<update>`                                                                                     |         R         |       |
-| `<gpg>`                                  | `<gpg>`                                                                                        |         R         |       |
 | `<repo>`                                 | `<repo>`                                                                                       |         R         |       |
 | `<repos>`                                | `<repos>`                                                                                      |         R         |       |
 | `<source_pkg>`                           | `<source_pkg>deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main</source_pkg>` |         R         |       |
@@ -999,27 +1051,27 @@ The query command can be used to gather information about the system and the Vis
 ```
 
 #### Source Application Remove Manifest Parameters
-| Tag                                      | Example                                  | Required/Optional | Notes |
-|:-----------------------------------------|:-----------------------------------------|:-----------------:|:------|
-| `<?xml version='1.0' encoding='utf-8'?>` | `<?xml version='1.0' encoding='utf-8'?>` |         R         |       |
-| `<manifest>`                             | `<manifest>`                             |         R         |       |
-| `<type></type>`                          | `<type>source</type>`                    |         R         |       |
-| `<applicationSource>`                    | `<applicationSource>`                    |         R         |       |
-| `<remove>`                               | `<remove>`                               |         R         |       |
-| `<gpg>`                                  | `<gpg>`                                  |         R         |       |
-| `<keyname></keyname>`                    | `<keyname>google-chrome.gpg</keyname>`   |         R         |       | 
-| `</gpg>`                                 | `<gpg>`                                  |         R         |       |
-| `<repo>`                                 | `<repo>`                                 |         R         |       |
-| `<filename></filename>`                  | `<filename>google-chrom.list</filename>` |         R         |       |
-| `</repo>`                                | `</repo>`                                |         R         |       |
-| `</remove>`                              | `</remove>`                              |         R         |       |
-| `</applicationSource>`                   | `</applicationSource>`                   |         R         |       |
-| `</manifest>`                            | `</manifest>`                            |         R         |       |
-
-
-
-
-#### Source Application Remove Manifest Example
+| Tag                                      | Example                                   | Required/Optional | Notes |
+|:-----------------------------------------|:------------------------------------------|:-----------------:|:------|
+| `<?xml version='1.0' encoding='utf-8'?>` | `<?xml version='1.0' encoding='utf-8'?>`  |         R         |       |
+| `<manifest>`                             | `<manifest>`                              |         R         |       |
+| `<type></type>`                          | `<type>source</type>`                     |         R         |       |
+| `<applicationSource>`                    | `<applicationSource>`                     |         R         |       |
+| `<remove>`                               | `<remove>`                                |         R         |       |
+| `<gpg>`                                  | `<gpg>`                                   |         O         |       |
+| `<keyname></keyname>`                    | `<keyname>google-chrome.gpg</keyname>`    |         O         |       | 
+| `</gpg>`                                 | `<gpg>`                                   |         O         |       |
+| `<repo>`                                 | `<repo>`                                  |         R         |       |
+| `<filename></filename>`                  | `<filename>google-chrome.list</filename>` |         R         |       |
+| `</repo>`                                | `</repo>`                                 |         R         |       |
+| `</remove>`                              | `</remove>`                               |         R         |       |
+| `</applicationSource>`                   | `</applicationSource>`                    |         R         |       |
+| `</manifest>`                            | `</manifest>`                             |         R         |       |
+
+
+
+
+#### Source Application Remove Manifest Example (Including GPG key)
 ```xml
 <?xml version="1.0" encoding="UTF-8"?>
 <manifest>
@@ -1037,6 +1089,21 @@ The query command can be used to gather information about the system and the Vis
 </manifest>
 ```
 
+#### Source Application Remove Manifest Example (Excluding GPG key)
+```xml
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest>
+    <type>source</type>
+    <applicationSource>
+        <remove>
+            <repo>
+                <filename>google-chrome.sources</filename>
+            </repo>
+        </remove>
+    </applicationSource>
+</manifest>
+```
+
 #### Source Application List Manifest Parameters
 | Tag                                      | Example                                  | Required/Optional | Notes |
 |:-----------------------------------------|:-----------------------------------------|:-----------------:|:------|
diff --git a/inbc-program/README.md b/inbc-program/README.md
index 4737645c6..4d36ab54d 100644
--- a/inbc-program/README.md
+++ b/inbc-program/README.md
@@ -414,20 +414,20 @@ inbc query --option sw
 
 ## SOURCE APPLICATION ADD
 ### Description
-Downloads and encrypts GPG key and stores it on the system under <em>/usr/share/keyrings</em>.  Creates a file under <em>/etc/apt/sources.list.d</em> to store the update source information.
-This list file is used during 'sudo apt update' to update the application
+Optionally Downloads and encrypts GPG key and stores it on the system under <em>/usr/share/keyrings</em>.  Creates a file under <em>/etc/apt/sources.list.d</em> to store the update source information.
+This list file is used during 'sudo apt update' to update the application.  <em>Deb882</em> format may be used instead of downloading a GPG key.
 
 ### Usage
 ```
-inbc source application add 
-   {--gpgKeyUri, -gku=GPG_KEY_URI}
-   {--gpgKeyName, -gkn=GPG_KEY_NAME}
+inbc source application add
    {--sources, -s=SOURCES}
    {--filename, -f=FILENAME}
+   [--gpgKeyUri, -gku=GPG_KEY_URI]
+   [--gpgKeyName, -gkn=GPG_KEY_NAME]
 ```
 
 ### Example
-#### Add an application source
+#### Add an Application Source (non-deb822 format with remote GPG key)
 ```
 inbc source application add 
    --gpgKeyUri https://dl-ssl.google.com/linux/linux_signing_key.pub 
@@ -436,25 +436,81 @@ inbc source application add
    --filename google-chrome.list
 ```
 
+#### Add an Application Source (using deb822 format)
+
+**NOTE:** In the Signed-By: Section, use the following guidelines.
+
+      - Each blank line has a period in it. -> " ."
+      - Each line after the Signed-By: starts with a space -> " gibberish"
+
+```
+inbc source application add 
+   --sources 
+      "Enabled: yes" 
+      "Types: deb"
+      "URIs: http://dl.google.com/linux/chrome/deb/" 
+      "Suites: stable" 
+      "Components: main" 
+      "Signed-By:" 
+      " -----BEGIN PGP PUBLIC KEY BLOCK-----" 
+      " Version: GnuPG v1.4.2.2 (GNU/Linux)" 
+      " ." 
+      " mQGiBEXwb0YRBADQva2NLpYXxgjNkbuP0LnPoEXruGmvi3XMIxjEUFuGNCP4Rj/a" 
+      " kv2E5VixBP1vcQFDRJ+p1puh8NU0XERlhpyZrVMzzS/RdWdyXf7E5S8oqNXsoD1z" 
+      " fvmI+i9b2EhHAA19Kgw7ifV8vMa4tkwslEmcTiwiw8lyUl28Wh4Et8SxzwCggDcA" 
+      " feGqtn3PP5YAdD0km4S4XeMEAJjlrqPoPv2Gf//tfznY2UyS9PUqFCPLHgFLe80u" 
+      " QhI2U5jt6jUKN4fHauvR6z3seSAsh1YyzyZCKxJFEKXCCqnrFSoh4WSJsbFNc4PN" 
+      " b0V0SqiTCkWADZyLT5wll8sWuQ5ylTf3z1ENoHf+G3um3/wk/+xmEHvj9HCTBEXP" 
+      " 78X0A/0Tqlhc2RBnEf+AqxWvM8sk8LzJI/XGjwBvKfXe+l3rnSR2kEAvGzj5Sg0X" 
+      " 4XmfTg4Jl8BNjWyvm2Wmjfet41LPmYJKsux3g0b8yzQxeOA4pQKKAU3Z4+rgzGmf" 
+      " HdwCG5MNT2A5XxD/eDd+L4fRx0HbFkIQoAi1J3YWQSiTk15fw7RMR29vZ2xlLCBJ" 
+      " bmMuIExpbnV4IFBhY2thZ2UgU2lnbmluZyBLZXkgPGxpbnV4LXBhY2thZ2VzLWtl" 
+      " eW1hc3RlckBnb29nbGUuY29tPohjBBMRAgAjAhsDBgsJCAcDAgQVAggDBBYCAwEC" 
+      " HgECF4AFAkYVdn8CGQEACgkQoECDD3+sWZHKSgCfdq3HtNYJLv+XZleb6HN4zOcF" 
+      " AJEAniSFbuv8V5FSHxeRimHx25671az+uQINBEXwb0sQCACuA8HT2nr+FM5y/kzI" 
+      " A51ZcC46KFtIDgjQJ31Q3OrkYP8LbxOpKMRIzvOZrsjOlFmDVqitiVc7qj3lYp6U" 
+      " rgNVaFv6Qu4bo2/ctjNHDDBdv6nufmusJUWq/9TwieepM/cwnXd+HMxu1XBKRVk9" 
+      " XyAZ9SvfcW4EtxVgysI+XlptKFa5JCqFM3qJllVohMmr7lMwO8+sxTWTXqxsptJo" 
+      " pZeKz+UBEEqPyw7CUIVYGC9ENEtIMFvAvPqnhj1GS96REMpry+5s9WKuLEaclWpd" 
+      " K3krttbDlY1NaeQUCRvBYZ8iAG9YSLHUHMTuI2oea07Rh4dtIAqPwAX8xn36JAYG" 
+      " 2vgLAAMFB/wKqaycjWAZwIe98Yt0qHsdkpmIbarD9fGiA6kfkK/UxjL/k7tmS4Vm" 
+      " CljrrDZkPSQ/19mpdRcGXtb0NI9+nyM5trweTvtPw+HPkDiJlTaiCcx+izg79Fj9" 
+      " KcofuNb3lPdXZb9tzf5oDnmm/B+4vkeTuEZJ//IFty8cmvCpzvY+DAz1Vo9rA+Zn" 
+      " cpWY1n6z6oSS9AsyT/IFlWWBZZ17SpMHu+h4Bxy62+AbPHKGSujEGQhWq8ZRoJAT" 
+      " G0KSObnmZ7FwFWu1e9XFoUCt0bSjiJWTIyaObMrWu/LvJ3e9I87HseSJStfw6fki" 
+      " 5og9qFEkMrIrBCp3QGuQWBq/rTdMuwNFiEkEGBECAAkFAkXwb0sCGwwACgkQoECD" 
+      " D3+sWZF/WACfeNAu1/1hwZtUo1bR+MWiCjpvHtwAnA1R3IHqFLQ2X3xJ40XPuAyY" 
+      " /FJG" 
+      " %20=Quqp" 
+      " -----END PGP PUBLIC KEY BLOCK-----"
+   --filename google-chrome.sources
+```
+
 ## SOURCE APPLICATION REMOVE
 ### Description
-Removes the GPG key file from under <em>/usr/share/keyrings</em>.  Removes the source file from under /etc/apt/sources.list.d/.
+Removes the source file from under /etc/apt/sources.list.d/.  Optionally removes the GPG key file from under <em>/usr/share/keyrings</em>. 
 
 ### Usage
 ```
-inbc source application remove 
-   {--gpgKeyName, -gkn=GPG_KEY_NAME} 
+inbc source application remove    
    {--filename, -f=FILE_NAME}
+   [--gpgKeyName, -gkn=GPG_KEY_NAME]
 ```
 
 ### Example
-#### Remove an application source
+#### Remove an application source (Both GPG key and Source File)
 ```commandline
 inbc source application remove 
     --gpgKeyName google-chrome.gpg 
     --filename google-chrome.list
 ```
 
+#### Remove an application source (deb822 format)
+```commandline
+inbc source application remove 
+    --filename google-chrome.sources
+```
+
 ## SOURCE APPLICATION UPDATE
 ### Description
 Updates Application sources that are used to update the system
@@ -478,7 +534,6 @@ inbc source application update
 ## SOURCE APPLICATION LIST
 ### Description
 Lists Application sources
-NOTE: Currently this only works on Ubuntu
 
 ### Usage
 ```
@@ -545,7 +600,6 @@ inbc source os update
 ## SOURCE OS LIST
 ### Description
 Lists OS sources
-NOTE: Currently this only works on Ubuntu
 
 ### Usage
 ```commandline
diff --git a/inbc-program/inbc/parser/parser.py b/inbc-program/inbc/parser/parser.py
index 97201444b..3f3208d50 100644
--- a/inbc-program/inbc/parser/parser.py
+++ b/inbc-program/inbc/parser/parser.py
@@ -65,11 +65,11 @@ def parse_source_args(self) -> None:
 
         # Application Add Command
         app_add_parser = app_subparsers.add_parser('add')
-        app_add_parser.add_argument('--gpgKeyUri', '-gku', required=True,
+        app_add_parser.add_argument('--gpgKeyUri', '-gku', required=False,
                                     type=lambda x: validate_string_less_than_n_characters(
                                         x, 'str', 1500),
                                     help='Uri from which to download GPG key')
-        app_add_parser.add_argument('--gpgKeyName', '-gkn', required=True,
+        app_add_parser.add_argument('--gpgKeyName', '-gkn', required=False,
                                     type=lambda x: validate_string_less_than_n_characters(
                                         x, 'str', 200),
                                     help='Name to store the GPG key information')
@@ -85,7 +85,7 @@ def parse_source_args(self) -> None:
 
         # Application Remove Command
         app_remove_parser = app_subparsers.add_parser('remove')
-        app_remove_parser.add_argument('--gpgKeyName', '-gkn', required=True,
+        app_remove_parser.add_argument('--gpgKeyName', '-gkn', required=False,
                                        type=lambda x: validate_string_less_than_n_characters(
                                            x, 'str', 50),
                                        help='GPG key name of the source to remove.')
diff --git a/inbc-program/inbc/parser/source_app_parser.py b/inbc-program/inbc/parser/source_app_parser.py
index 680dd4615..3702f3690 100644
--- a/inbc-program/inbc/parser/source_app_parser.py
+++ b/inbc-program/inbc/parser/source_app_parser.py
@@ -4,11 +4,19 @@
    SPDX-License-Identifier: Apache-2.0
 """
 import argparse
+import logging
 
+from ..inbc_exception import InbcException
 from ..xml_tag import create_xml_tag
 
+logger = logging.getLogger(__name__)
+
 
 def application_add(args: argparse.Namespace) -> str:
+    if (args.gpgKeyUri and args.gpgKeyName is None) or (args.gpgKeyName and args.gpgKeyUri is None):
+        raise InbcException(
+            "Source requires either both gpgKeyUri and gpgKeyName to be provided, or neither of them.")
+
     arguments = {
         'uri': args.gpgKeyUri,
         'keyname': args.gpgKeyName,
@@ -19,15 +27,16 @@ def application_add(args: argparse.Namespace) -> str:
     manifest = ('<?xml version="1.0" encoding="utf-8"?>' +
                 '<manifest>' +
                 '<type>source</type>' +
-                '<applicationSource>' +
-                '<add><gpg>'
-                '{0}' +
-                '{1}'
-                '</gpg><repo><repos>').format(create_xml_tag(arguments, "uri"),
-                                              create_xml_tag(arguments, "keyname"))
+                '<applicationSource>' + '<add>')
+
+    if args.gpgKeyUri and args.gpgKeyName:
+        manifest += ('<gpg>' + '{0}' + '{1}' + '</gpg>').format(create_xml_tag(arguments, "uri"),
+                                                                create_xml_tag(arguments, "keyname"))
+
+    manifest += '<repo><repos>'
 
     for source in args.sources:
-        manifest += '<source_pkg>' + source.strip() + '</source_pkg>'
+        manifest += '<source_pkg>' + source + '</source_pkg>'
 
     manifest += ('</repos>'
                  f'{create_xml_tag(arguments, "filename")}</repo>'
@@ -47,13 +56,16 @@ def application_remove(args: argparse.Namespace) -> str:
     manifest = ('<?xml version="1.0" encoding="utf-8"?>' +
                 '<manifest><type>source</type>' +
                 '<applicationSource>' +
-                '<remove><gpg>'
-                f'{create_xml_tag(arguments, "keyname")}' +
-                '</gpg><repo>' +
-                f'{create_xml_tag(arguments, "filename")}'
-                '</repo>'
-                '</remove></applicationSource>' +
-                '</manifest>')
+                '<remove>')
+
+    if args.gpgKeyName:
+        manifest += f'<gpg>{create_xml_tag(arguments, "keyname")}</gpg>'
+
+    manifest += ('<repo>' +
+                 f'{create_xml_tag(arguments, "filename")}'
+                 '</repo>'
+                 '</remove></applicationSource>' +
+                 '</manifest>')
 
     print(f"manifest {manifest}")
     return manifest
diff --git a/inbc-program/tests/unit/test_source_app_parser.py b/inbc-program/tests/unit/test_source_app_parser.py
index 43cfbaeb8..c16d98595 100644
--- a/inbc-program/tests/unit/test_source_app_parser.py
+++ b/inbc-program/tests/unit/test_source_app_parser.py
@@ -1,8 +1,10 @@
+import pytest
 from unittest import TestCase
 from unittest.mock import patch
 
 from inbc.inbc import Inbc
 from inbc.parser.parser import ArgsParser
+from inbc.inbc_exception import InbcException
 
 
 class TestSourceApplicationParser(TestCase):
@@ -10,7 +12,7 @@ def setUp(self):
         self.arg_parser = ArgsParser()
         self.maxDiff = None
 
-    def test_parse_add_arguments_successfully(self):
+    def test_parse_add_all_arguments_successfully(self):
         f = self.arg_parser.parse_args(
             ['source', 'application', 'add',
              '--gpgKeyUri', 'https://repositories.intel.com/gpu/intel-graphics.key',
@@ -24,8 +26,76 @@ def test_parse_add_arguments_successfully(self):
                                      'deb-src http://example.com/ focal-security main'])
         self.assertEqual(f.filename, 'intel-gpu-jammy.list')
 
+    def test_parse_add_arguments_deb822_format_separate_lines_successfully(self):
+        f = self.arg_parser.parse_args(
+            ['source', 'application', 'add',
+             '--sources', 'X-Repolib-Name: Google Chrome',
+                          'Enabled: yes',
+                          'Types: deb',
+                          'URIs: https://dl-ssl.google.com/linux/linux_signing_key.pub',
+                          'Suites: stable',
+                          'Components: main',
+             '--filename', 'intel-gpu-jammy.list'])
+        self.assertEqual(f.gpgKeyUri, None)
+        self.assertEqual(f.gpgKeyName, None)
+        self.assertEqual(f.sources, ['X-Repolib-Name: Google Chrome',
+                                     'Enabled: yes',
+                                     'Types: deb',
+                                     'URIs: https://dl-ssl.google.com/linux/linux_signing_key.pub',
+                                     'Suites: stable',
+                                     'Components: main'])
+        self.assertEqual(f.filename, 'intel-gpu-jammy.list')
+
+    @patch('inbm_lib.mqttclient.mqtt.mqtt.Client.connect')
+    def test_raise_application_add_with_only_one_gpgKeyUri_param(self, m_connect):
+        p = self.arg_parser.parse_args(
+            ['source', 'application', 'add',
+             '--gpgKeyUri', 'https://repositories.intel.com/gpu/intel-graphics.key',
+             '--sources', 'deb http://example.com/ focal main restricted universe',
+             'deb-src http://example.com/ focal-security main',
+             '--filename', 'intel-gpu-jammy.list'])
+        with pytest.raises(InbcException,
+                           match="Source requires either both gpgKeyUri and gpgKeyName "
+                                 "to be provided, or neither of them."):
+            Inbc(p, 'source', False)
+
+    @patch('inbm_lib.mqttclient.mqtt.mqtt.Client.connect')
+    def test_raise_application_add_with_only_one_gpgKeyName_param(self, m_connect):
+        p = self.arg_parser.parse_args(
+            ['source', 'application', 'add',
+             '--gpgKeyName', 'intel-graphics.gpg',
+             '--sources', 'deb http://example.com/ focal main restricted universe',
+             'deb-src http://example.com/ focal-security main',
+             '--filename', 'intel-gpu-jammy.list'])
+        with pytest.raises(InbcException,
+                           match="Source requires either both gpgKeyUri and gpgKeyName "
+                                 "to be provided, or neither of them."):
+            Inbc(p, 'source', False)
+
+    @patch('inbm_lib.mqttclient.mqtt.mqtt.Client.connect')
+    def test_create_add_deb_822_format_manifest_successfully(self, m_connect):
+        p = self.arg_parser.parse_args(
+            ['source', 'application', 'add',
+             '--sources', 'X-Repolib-Name: Google Chrome',
+                          'Enabled: yes',
+                          'Types: deb',
+                          'URIs: https://dl-ssl.google.com/linux/linux_signing_key.pub',
+                          'Suites: stable',
+                          'Components: main',
+             '--filename', 'google-chrome.sources'])
+        Inbc(p, 'source', False)
+        expected = '<?xml version="1.0" encoding="utf-8"?><manifest><type>source</type><applicationSource>' \
+                   '<add><repo><repos><source_pkg>X-Repolib-Name: Google Chrome</source_pkg>' \
+                   '<source_pkg>Enabled: yes</source_pkg>' \
+                   '<source_pkg>Types: deb</source_pkg>'\
+                   '<source_pkg>URIs: https://dl-ssl.google.com/linux/linux_signing_key.pub</source_pkg>' \
+                   '<source_pkg>Suites: stable</source_pkg>' \
+                   '<source_pkg>Components: main</source_pkg>' \
+                   '</repos><filename>google-chrome.sources</filename></repo></add></applicationSource></manifest>'
+        self.assertEqual(p.func(p), expected)
+
     @patch('inbm_lib.mqttclient.mqtt.mqtt.Client.connect')
-    def test_create_add_manifest_successfully(self, m_connect):
+    def test_create_add_all_param_manifest_successfully(self, m_connect):
         p = self.arg_parser.parse_args(
             ['source', 'application', 'add',
              '--gpgKeyUri', 'https://repositories.intel.com/gpu/intel-graphics.key',
@@ -42,7 +112,22 @@ def test_create_add_manifest_successfully(self, m_connect):
                    '</repos><filename>intel-gpu-jammy.list</filename></repo></add></applicationSource></manifest>'
         self.assertEqual(p.func(p), expected)
 
-    def test_parse_remove_arguments_successfully(self):
+    @patch('inbm_lib.mqttclient.mqtt.mqtt.Client.connect')
+    def test_create_add_minus_gpg_manifest_successfully(self, m_connect):
+        p = self.arg_parser.parse_args(
+            ['source', 'application', 'add',
+             '--sources', 'deb http://example.com/ focal main restricted universe',
+             'deb-src http://example.com/ focal-security main',
+             '--filename', 'intel-gpu-jammy.list'])
+        Inbc(p, 'source', False)
+        expected = '<?xml version="1.0" encoding="utf-8"?><manifest><type>source</type><applicationSource>' \
+                   '<add><repo><repos>' \
+                   '<source_pkg>deb http://example.com/ focal main restricted universe</source_pkg>' \
+                   '<source_pkg>deb-src http://example.com/ focal-security main</source_pkg>' \
+                   '</repos><filename>intel-gpu-jammy.list</filename></repo></add></applicationSource></manifest>'
+        self.assertEqual(p.func(p), expected)
+
+    def test_parse_all_remove_arguments_successfully(self):
         f = self.arg_parser.parse_args(
             ['source', 'application', 'remove',
              '--gpgKeyName', 'intel-gpu-jammy.gpg',
@@ -50,8 +135,15 @@ def test_parse_remove_arguments_successfully(self):
         self.assertEqual(f.gpgKeyName, 'intel-gpu-jammy.gpg')
         self.assertEqual(f.filename, 'intel-gpu-jammy.list')
 
+    def test_parse_minus_gpg_remove_arguments_successfully(self):
+        f = self.arg_parser.parse_args(
+            ['source', 'application', 'remove',
+             '--filename', 'intel-gpu-jammy.list'])
+        self.assertEqual(f.gpgKeyName, None)
+        self.assertEqual(f.filename, 'intel-gpu-jammy.list')
+
     @patch('inbm_lib.mqttclient.mqtt.mqtt.Client.connect')
-    def test_create_remove_manifest_successfully(self, m_connect):
+    def test_create_remove_manifest_all_params_successfully(self, m_connect):
         p = self.arg_parser.parse_args(
             ['source', 'application', 'remove',
              '--gpgKeyName', 'intel-gpu-jammy.gpg',
@@ -62,6 +154,16 @@ def test_create_remove_manifest_successfully(self, m_connect):
                    '<repo><filename>intel-gpu-jammy.list</filename></repo></remove></applicationSource></manifest>'
         self.assertEqual(p.func(p), expected)
 
+    @patch('inbm_lib.mqttclient.mqtt.mqtt.Client.connect')
+    def test_create_remove_manifest_minus_gpg_successfully(self, m_connect):
+        p = self.arg_parser.parse_args(
+            ['source', 'application', 'remove',
+             '--filename', 'intel-gpu-jammy.list'])
+        Inbc(p, 'source', False)
+        expected = '<?xml version="1.0" encoding="utf-8"?><manifest><type>source</type><applicationSource><remove>' \
+                   '<repo><filename>intel-gpu-jammy.list</filename></repo></remove></applicationSource></manifest>'
+        self.assertEqual(p.func(p), expected)
+
     def test_parse_update_arguments_successfully(self):
         f = self.arg_parser.parse_args(
             ['source', 'application', 'update',
diff --git a/inbm/dispatcher-agent/dispatcher/source/constants.py b/inbm/dispatcher-agent/dispatcher/source/constants.py
index 3d7d3f94c..908aab9cb 100644
--- a/inbm/dispatcher-agent/dispatcher/source/constants.py
+++ b/inbm/dispatcher-agent/dispatcher/source/constants.py
@@ -6,6 +6,7 @@
 
 from enum import Enum, unique
 from dataclasses import dataclass, field
+from typing import Optional
 
 UBUNTU_APT_SOURCES_LIST = "/etc/apt/sources.list"
 UBUNTU_APT_SOURCES_LIST_D = "/etc/apt/sources.list.d"
@@ -25,16 +26,16 @@ class SourceParameters:
 
 @dataclass(kw_only=True, frozen=True)
 class ApplicationAddSourceParameters:
-    gpg_key_uri: str
-    gpg_key_name: str
     file_name: str
     sources: list[str] = field(default_factory=lambda: [])
+    gpg_key_uri: Optional[str] = field(default=None)
+    gpg_key_name: Optional[str] = field(default=None)
 
 
 @dataclass(kw_only=True, frozen=True)
 class ApplicationRemoveSourceParameters:
-    gpg_key_name: str
     file_name: str
+    gpg_key_name: Optional[str] = field(default=None)
 
 
 @dataclass(kw_only=True, frozen=True)
diff --git a/inbm/dispatcher-agent/dispatcher/source/source_command.py b/inbm/dispatcher-agent/dispatcher/source/source_command.py
index 2f90e0e7e..4b30b5cc8 100644
--- a/inbm/dispatcher-agent/dispatcher/source/source_command.py
+++ b/inbm/dispatcher-agent/dispatcher/source/source_command.py
@@ -54,7 +54,7 @@ def _handle_os_source_command(parsed_head: XmlHandler, os_type: OsType, os_actio
     Handle the os source commands.
 
     @param parsed_head: XmlHandler with command information
-    @param os_type: os type
+    @param os_type: OS type
     @param os_action: The action to be performed
     @return Result
     """
@@ -94,8 +94,7 @@ def _handle_os_source_command(parsed_head: XmlHandler, os_type: OsType, os_actio
 
 
 def _handle_app_source_command(
-    parsed_head: XmlHandler, os_type: OsType, app_action: dict
-) -> Result:
+        parsed_head: XmlHandler, os_type: OsType, app_action: dict) -> Result:
     """
     Handle the application source commands.
 
@@ -113,7 +112,12 @@ def _handle_app_source_command(
         return Result(status=200, message=serialized_list)
 
     if "remove" in app_action:
-        keyname = parsed_head.get_children("applicationSource/remove/gpg")["keyname"]
+        keyname = None
+        try:
+            keyname = parsed_head.get_children("applicationSource/remove/gpg")["keyname"]
+        except XmlException:
+            # These children may not be present
+            logger.info(f"Optional GPG key parameters not present in manifest")
         filename = parsed_head.get_children("applicationSource/remove/repo")["filename"]
         application_source_manager.remove(
             ApplicationRemoveSourceParameters(file_name=filename, gpg_key_name=keyname)
@@ -121,8 +125,16 @@ def _handle_app_source_command(
         return Result(status=200, message="SUCCESS")
 
     if "add" in app_action:
-        gpg_key_uri = parsed_head.get_children("applicationSource/add/gpg")["uri"]
-        gpg_key_name = parsed_head.get_children("applicationSource/add/gpg")["keyname"]
+        gpg_key_uri = None
+        gpg_key_name = None
+
+        try:
+            gpg_key_uri = parsed_head.get_children("applicationSource/add/gpg")["uri"]
+            gpg_key_name = parsed_head.get_children("applicationSource/add/gpg")["keyname"]
+        except XmlException:
+            # These children may not be present
+            logger.info(f"Optional GPG key parameters not present in manifest")
+
         repo_filename = parsed_head.get_children("applicationSource/add/repo")["filename"]
 
         add_source_pkgs: list[str] = []
diff --git a/inbm/dispatcher-agent/dispatcher/source/ubuntu_source_manager.py b/inbm/dispatcher-agent/dispatcher/source/ubuntu_source_manager.py
index 220b8be3f..8838ff58a 100644
--- a/inbm/dispatcher-agent/dispatcher/source/ubuntu_source_manager.py
+++ b/inbm/dispatcher-agent/dispatcher/source/ubuntu_source_manager.py
@@ -23,7 +23,6 @@
 from inbm_common_lib.utility import (
     get_canonical_representation_of_path,
     remove_file,
-    move_file,
     create_file_with_contents,
 )
 
@@ -98,8 +97,10 @@ def __init__(self) -> None:
         pass
 
     def add(self, parameters: ApplicationAddSourceParameters) -> None:
-        # Step 1: Add key
-        add_gpg_key(parameters.gpg_key_uri, parameters.gpg_key_name)
+        """Adds a source file and optional GPG key to be used during Ubuntu application updates."""
+        # Step 1: Add key (Optional)
+        if parameters.gpg_key_name and parameters.gpg_key_uri:
+            add_gpg_key(parameters.gpg_key_uri, parameters.gpg_key_name)
 
         # Step 2: Add the source
         try:
@@ -134,11 +135,13 @@ def list(self) -> list[ApplicationSourceList]:
             raise SourceError(f"Error listing application sources: {e}") from e
 
     def remove(self, parameters: ApplicationRemoveSourceParameters) -> None:
-        """Removes a source file from the Ubuntu source file list under /etc/apt/sources.list.d
+        """Removes a source file from the Ubuntu source file list under /etc/apt/sources.list.d.  Optionally
+        removes the gpg key from /usr/share/keyrings
         @parameters: dataclass parameters for ApplicationRemoveSourceParameters
         """
-        # Remove the GPG key
-        remove_gpg_key_if_exists(parameters.gpg_key_name)
+        if parameters.gpg_key_name:
+            # Remove the GPG key (Optional)
+            remove_gpg_key_if_exists(parameters.gpg_key_name)
 
         # Remove the file under /etc/apt/sources.list.d
         try:
diff --git a/inbm/dispatcher-agent/fpm-template/usr/share/dispatcher-agent/manifest_schema.xsd b/inbm/dispatcher-agent/fpm-template/usr/share/dispatcher-agent/manifest_schema.xsd
index 6a8fad59b..36ce3c38a 100644
--- a/inbm/dispatcher-agent/fpm-template/usr/share/dispatcher-agent/manifest_schema.xsd
+++ b/inbm/dispatcher-agent/fpm-template/usr/share/dispatcher-agent/manifest_schema.xsd
@@ -319,11 +319,11 @@
                             <xs:element name="add" minOccurs="1" maxOccurs="1">
                                 <xs:complexType>
                                     <xs:sequence>
-                                        <xs:element name="gpg" minOccurs="1" maxOccurs="1">
+                                        <xs:element name="gpg" minOccurs="0" maxOccurs="1">
                                             <xs:complexType>
                                                 <xs:sequence>
-                                                    <xs:element name="uri" type="PathMax1500Chars" minOccurs="1" maxOccurs="1"/>
-                                                    <xs:element name="keyname" type="Max200Chars" minOccurs="1" maxOccurs="1"/>
+                                                    <xs:element name="uri" type="PathMax1500Chars" minOccurs="0" maxOccurs="1"/>
+                                                    <xs:element name="keyname" type="Max200Chars" minOccurs="0" maxOccurs="1"/>
                                                 </xs:sequence>
                                             </xs:complexType>
                                         </xs:element>
@@ -333,7 +333,7 @@
                                                     <xs:element name="repos" minOccurs="1" maxOccurs="1">
                                                         <xs:complexType>
                                                             <xs:sequence>
-                                                                <xs:element name="source_pkg" type="Max200Chars" minOccurs="1" maxOccurs="2"/>
+                                                                <xs:element name="source_pkg" type="Max200Chars" minOccurs="1" maxOccurs="45"/>
                                                             </xs:sequence>
                                                         </xs:complexType>
                                                     </xs:element>
@@ -353,7 +353,7 @@
                                                     <xs:element name="repos" minOccurs="1" maxOccurs="1">
                                                         <xs:complexType>
                                                             <xs:sequence>
-                                                                <xs:element name="source_pkg" type="Max200Chars" minOccurs="1" maxOccurs="2"/>
+                                                                <xs:element name="source_pkg" type="Max200Chars" minOccurs="1" maxOccurs="45"/>
                                                             </xs:sequence>
                                                         </xs:complexType>
                                                     </xs:element>
@@ -367,10 +367,10 @@
                             <xs:element name="remove" minOccurs="1" maxOccurs="1">
                                 <xs:complexType>
                                     <xs:sequence>
-                                        <xs:element name="gpg" minOccurs="1" maxOccurs="1">
+                                        <xs:element name="gpg" minOccurs="0" maxOccurs="1">
                                             <xs:complexType>
                                                 <xs:sequence>
-                                                    <xs:element name="keyname" type="Max50Chars" minOccurs="1" maxOccurs="1"/>
+                                                    <xs:element name="keyname" type="Max50Chars" minOccurs="0" maxOccurs="1"/>
                                                 </xs:sequence>
                                             </xs:complexType>
                                         </xs:element>
diff --git a/inbm/dispatcher-agent/tests/unit/source/test_ubuntu_source_cmd.py b/inbm/dispatcher-agent/tests/unit/source/test_ubuntu_source_cmd.py
index 9206154f9..933e37379 100644
--- a/inbm/dispatcher-agent/tests/unit/source/test_ubuntu_source_cmd.py
+++ b/inbm/dispatcher-agent/tests/unit/source/test_ubuntu_source_cmd.py
@@ -8,6 +8,7 @@
     ApplicationRemoveSourceParameters,
     SourceParameters,
     ApplicationUpdateSourceParameters,
+    ApplicationAddSourceParameters
 )
 from dispatcher.source.ubuntu_source_manager import (
     UbuntuApplicationSourceManager,
@@ -192,14 +193,44 @@ def test_update_sources_os_error(self):
 
 
 class TestUbuntuApplicationSourceManager:
-    @patch("dispatcher.source.ubuntu_source_manager.move_file")
-    def test_update_app_source_successfully(self, mock_move):
+    def test_add_app_with_gpg_key_successfully(self):
+        try:
+            params = ApplicationAddSourceParameters(
+                file_name="intel-gpu-jammy.list",
+                sources="deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main",
+                gpg_key_uri="https://dl-ssl.google.com/linux/linux_signing_key.pub",
+                gpg_key_name="google-chrome.gpg"
+            )
+            command = UbuntuApplicationSourceManager()
+            with patch("builtins.open", new_callable=mock_open()):
+                command.add(params)
+        except SourceError as err:
+            assert False, f"'UbuntuApplicationSourceManager.add' raised an exception {err}"
+
+    def test_add_app_deb_822_format_successfully(self):
+        try:
+            params = ApplicationAddSourceParameters(
+                file_name="google-chrome.sources",
+                sources="X-Repolib-Name: Google Chrome"
+                        "Enabled: yes"
+                        "Types: deb"
+                        "URIs: https://dl-ssl.google.com/linux/linux_signing_key.pub"
+                        "Suites: stable"
+                        "Components: main",
+            )
+            command = UbuntuApplicationSourceManager()
+            with patch("builtins.open", new_callable=mock_open()):
+                command.add(params)
+        except SourceError as err:
+            assert False, f"'UbuntuApplicationSourceManager.add' raised an exception {err}"
+
+    def test_update_app_source_successfully(self):
         try:
             params = ApplicationUpdateSourceParameters(
                 file_name="intel-gpu-jammy.list", sources=APP_SOURCE
             )
             command = UbuntuApplicationSourceManager()
-            with patch("builtins.open", new_callable=mock_open()) as m:
+            with patch("builtins.open", new_callable=mock_open()):
                 command.update(params)
         except SourceError as err:
             assert False, f"'UbuntuApplicationSourceManager.update' raised an exception {err}"
diff --git a/inbm/integration-reloaded/README.md b/inbm/integration-reloaded/README.md
index 1cb2c9ed5..3a96a3a1b 100644
--- a/inbm/integration-reloaded/README.md
+++ b/inbm/integration-reloaded/README.md
@@ -1,20 +1,20 @@
 # Introduction
 
-integration-reloaded is sub-project within 'inb' which helps create a Ubuntu 20.04 or 22.04 server environment 
+integration-reloaded is subproject within 'inb' which helps create a Ubuntu 20.04 or 22.04 server environment 
 with a BTRFS file system (mounted as / )
 
 # Uses
 
 1. It can be used as a test box for testing 'inb' artifacts
 2. Demo machine
-3. Currently being used as a part of iotg-inb's CI system.
+3. It is currently being used as a part of iotg-inb's CI system.
 
 # Local setup
 
-If you want to setup a system ready to go with a click of a button...you will have to perform a one-time setup 
+If you want to set up a system ready to go with a click of a button...you will have to perform a one-time setup 
 on your local dev system
 
-## Pre-requistes:
+## Pre-requisites:
 Installing Vagrant, Vagrant-libvirt, Qmenu-KVM and the plugins etc
 
 1. Download vagrant from vagrant https://www.vagrantup.com/downloads.html and
@@ -22,12 +22,12 @@ Installing Vagrant, Vagrant-libvirt, Qmenu-KVM and the plugins etc
 
 2. Edit the /etc/apt/sources.list and uncomment all the deb-src lines
 
-3. Run the below commands in sequence (preferrably as root)
+3. Run the below commands in sequence (preferably as root)
 ``` 
     apt update
-    apt install qemu qemu-kvm libvirt-bin
+    apt install qemu qemu-kvm libvirt-daemon-system libvirt-clients
     apt-get build-dep vagrant ruby-libvirt
-    apt-get install qemu libvirt-bin ebtables dnsmasq
+    apt-get install qemu libvirt-daemon-system libvirt-clients ebtables dnsmasq
     apt-get install libxslt-dev libvirt-dev zlib1g-dev ruby-dev
 ```
 
@@ -38,8 +38,8 @@ vagrant plugin install vagrant-libvirt
 ```
 
 ## How to use it
-1. Clone the iotg-inb repo
-2. `cd ~/iotg-inb/integration-reloaded`
+1. Clone the `intel-inb-manageability` repo
+2. `cd ~/intel-inb-manageability/inbm/integration-reloaded`
 3. Create a folder in integration-reloaded called `input`
 4. Download all the iotg-inb artifacts in that `input` folder and unzip the artifacts 
 5. export your docker username as DOCKER_USERNAME and your docker password as DOCKER_PASSWORD
diff --git a/inbm/integration-reloaded/test/source/SOURCE.sh b/inbm/integration-reloaded/test/source/SOURCE.sh
index c19cef04d..e8c69ef13 100755
--- a/inbm/integration-reloaded/test/source/SOURCE.sh
+++ b/inbm/integration-reloaded/test/source/SOURCE.sh
@@ -16,6 +16,7 @@ OPERA_KEY_NAME="opera.gpg"
 OPERA_SOURCES="deb [arch=amd64 signed-by=/usr/share/keyrings/$OPERA_KEY_NAME] https://deb.opera.com/opera-stable/ stable non-free"
 OPERA_LIST="opera.list"
 NEW_APP_SOURCE="deb newsource"
+CHROME_SOURCES_FILE="google-chrome.sources"
 
 cp "$APT_SOURCES" "$BAK_APT_SOURCES"
 
@@ -56,12 +57,26 @@ fi
 inbc source application list 2>&1 | grep "$OPERA_KEY_NAME"
 inbc source application remove --gpgKeyName "$OPERA_KEY_NAME" --filename "$OPERA_LIST"
 
+inbc source application add --filename $CHROME_SOURCES_FILE --sources \"Enabled: yes\" \"Types: deb\" \"URIs: http://dl.google.com/linux/chrome/deb/\" \"Suites: stable\" \"Components: main\"
+
+if [ ! -e "/etc/apt/sources.list.d/$CHROME_SOURCES_FILE" ]; then
+    echo "Error: The file '/etc/apt/sources.list.d/$CHROME_SOURCES_FILE' does not exist!"
+    exit 1
+fi
+inbc source application remove --filename "$CHROME_SOURCES_FILE"
+
 if inbc source application list 2>&1 | grep -q "$OPERA_KEY_NAME"; then
     echo "Error: $OPERA_KEY_NAME should not be present in the application list after removal"
     exit 1
 fi
 
+if inbc source application list 2>&1 | grep -q "$CHROME_SOURCES_FILE"; then
+    echo "Error: $CHROME_SOURCES_FILE should not be present in the application list after removal"
+    exit 1
+fi
+
 inbc source application add --gpgKeyUri "$OPERA_KEY_URI" --gpgKeyName "$OPERA_KEY_NAME" --sources "$OPERA_SOURCES" --filename "$OPERA_LIST"
+
 inbc source application update --sources "$NEW_APP_SOURCE" --filename "$OPERA_LIST"
 inbc source application list 2>&1 | grep "$NEW_APP_SOURCE"