Skip to main content

Sophos Firewall Python SDK

The Sophos Firewall Python Software Development Kit (SDK) provides a Python module for working with the XML API of Sophos Firewall.

For installation and usage details please see the documentation

Support

The Sophos Firewall Python SDK was developed by a small community of engineers within Sophos who will be maintaining the project. Questions can be posted to the Q&A section of the Github project. If you are hitting a bug, please open a new Issue and fill out the Bug Report template. If you would like to see a new feature implemented, please fill out the Feature Request template.

This project will utilize a community support model as outlined above. Support will not be provided by Sophos Technical Support.

Contributing

We welcome contributors to the project. To work on a new feature, fork the project and then develop your feature within the fork. When the new feature is ready for review, please submit a Pull Request.

To be merged into the project, the following requirements must be met:

  • Passing Pylint tests
  • Code formatted with Black
  • Unit tests written with Pytest

Development

The main code to be updated when developing new features is inside of the SophosFirewall class, which is located in the firewallapi.py module. Functionality is implemented by defining methods under the class. There are currently three types of methods: GET, CREATE, and UPDATE. The API Documentation describes how the API calls are structured.

GET Methods

GET methods provide retrieval of existing firewall configuration settings. They are implemented by calling the get_tag and/or the get_tag_with_filter methods of the class. The get_tag method requests a specified XML tag from the API and returns the content as a Python dict object. The get_tag will return all objects for the specified XML tag. The get_tag_with_filter method requests an XML tag from the API with specified filter criteria such as =, !=, or like. This allows for filtering of the returned data. Below is an example of a GET method that requests IP Hosts from the firewall using the IPHost XML tag. It utilizes both the get_tag and the get_tag_with_filter class methods, depending on the options provided to the method. If the calling program specifies no options, then all records are returned using the get_tag method. Otherwise, the results can be filtered by specifying the name or IP address. When name or IP address are provided, the get_tag_with_filter method is used to filter the results.

    def get_ip_host(
        self, name: str = None, ip_address: str = None, operator: str = "="):
        """Get IP Host object(s)

        Args:
            name (str, optional): IP object name. Returns all objects if not specified.
            ip_address (str, optional): Query by IP Address.
            operator (str, optional): Operator for search. Default is "=". Valid operators: =, !=, like. 
        """
        if name:
            return self.get_tag_with_filter(
                xml_tag="IPHost", key="Name", value=name, operator=operator
            )
        if ip_address:
            return self.get_tag_with_filter(
                xml_tag="IPHost",
                key="IPAddress",
                value=ip_address,
                operator=operator,
            )
        return self.get_tag(xml_tag="IPHost")

CREATE Methods

Create methods are used to create new configuration objects on the firewall. To define a new Create method, the XML payload for the request must first be created in a template and stored in the templates directory. The XML payload in the template can contain Jinja variables that will be populated when the template is rendered. Below is an example template containing the XML payload to create an IP Host. In the template, the values within the double brackets {{ var }} are variables that are passed in by the create method arguments.

<Request>
   <Login>
        <Username>{{username}}</Username>
        <Password >{{password}}</Password>
    </Login>
    <Set operation="add"> 
    <IPHost transactionid="">
        <Name>{{ name }}</Name>
        <IPFamily>IPv4</IPFamily>
        <HostType>IP</HostType>
        <IPAddress>{{ ip_address }}</IPAddress>
    </IPHost>
   </Set>
</Request>

Once the template is defined, a new create method can be written using the submit_template method. The submit_template method will render the template, passing in any variables that are specified in the new create method. It will then issue a POST request against the firewall API to create the new object.

Below is the method to create an IP Host. The source program must specify the name and ip_address as arguments when calling the function. These values are then populated in a dictionary called params and are passed to the submit_template method. There is also an optional debug argument which causes the API response to be output to screen for troubleshooting purposes.

def create_ip_host(
    self, name: str, ip_address: str, debug: bool = False
):
    """Create IP address object

    Args:
        name (str): Name of the object
        ip_address (str): Host IP address
        debug (bool, optional): Turn on debugging. Defaults to False.
    Returns:
        dict: XML response converted to Python dictionary
    """
    self._validate_ip_address(ip_address)

    params = {"name": name, "ip_address": ip_address}
    resp = self.submit_template(
        "createiphost.j2", template_vars=params, debug=debug
    )
    return resp

UPDATE Methods

Update methods provide the ability to change existing configuration on the firewall. When defining update methods, it is often necessary to first do a GET request to retrieve the existing configuration. This is because often the existing configuration must be in the payload in addition to any modifications. For example, when updating a URL Group with a new entry, the list must contain the existing entries along with the new one. Otherwise, the list will only contain the new entry when updated. Update methods can therefore first use an existing get method if defined, or can use the get_tag and/or get_tag_with_filter methods. Then, the information from the get request can be parsed and modified as necessary. Finally, the template can be submitted with the submit_template method, using the modified variables from the get request when rendering the template.

Below is the code to update a URL Group on the firewall. It first does a get request using the existing get_urlgroup method. It parses the existing list of URLs from the response, and then adds the new domain to the list. Finally, it uses the submit_template method to submit the updateurlgroup.j2 template, passing in as variables the name of the list to be updated and the updated domain list.

    def update_urlgroup(
        self, name: str, domain: str, debug: bool = False
    ):
        """Adds a specified domain to a web URL Group

        Args:
            name (str): URL Group name
            domain (str): Domain to be added to URL Group
            debug (bool, optional): Enable debug mode. Defaults to False.

        Returns:
            dict: XML response converted to Python dictionary
        """
        # Get the existing URL list first, if any
        resp = self.get_urlgroup(name=name)
        if "URLlist" in resp["Response"]["WebFilterURLGroup"]:
            exist_list = (
                resp.get("Response").get("WebFilterURLGroup").get("URLlist").get("URL")
            )
        else:
            exist_list = None
        domain_list = []
        if exist_list:
            if isinstance(exist_list, str):
                domain_list.append(exist_list)
            elif isinstance(exist_list, list):
                domain_list = exist_list
        domain_list.append(domain)

        params = {"name": name, "domain_list": domain_list}
        resp = self.submit_template(
            "updateurlgroup.j2", template_vars=params, debug=debug
        )
        return resp

Testing

Unit Tests

Pytest test cases are in the unittests.py module. The tests are executed by Github Actions on commits to the develop and/or main branch. It is not required to create new tests for Get methods, but it is recommended for Create or Update methods. Success and failure cases should be covered. The existing tests utilize the methods under test with sample input data and compare against a mocked API response. Please see the test_create_rule and test_failed_create_rule tests in the unittests.py for reference.

Functional Tests

Functional tests can be run against an actual firewall to ensure SDK functions are working properly. The functional tests are also run with Pytest, and require a few environment variables to connect to the target firewall:

export XG_USERNAME="<your firewall username>"
export XG_PASSWORD="<your firewall password>"
export XG_HOSTNAME="<your firewall hostname>"

To run the functional tests:

pytest sophosfirewall_python/tests/functional.py -s -vv

The tests will create objects on the firewall prefixed with FUNC_. At the end of the test run, these objects will be deleted.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sophosfirewall_python-0.1.68.tar.gz (58.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sophosfirewall_python-0.1.68-py3-none-any.whl (84.0 kB view details)

Uploaded Python 3

File details

Details for the file sophosfirewall_python-0.1.68.tar.gz.

File metadata

  • Download URL: sophosfirewall_python-0.1.68.tar.gz
  • Upload date:
  • Size: 58.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for sophosfirewall_python-0.1.68.tar.gz
Algorithm Hash digest
SHA256 8df25f09f23f520e9291146bf2f2f54b86e9cacb65ced9a41443ea06d7f5a7c1
MD5 f880d01bf1664268d1299bd44fb2d86f
BLAKE2b-256 542db81cb9483f8dcc3e83be5ae0bfe3ae0f1917d219f04a96c90703b42e6b62

See more details on using hashes here.

Provenance

The following attestation bundles were made for sophosfirewall_python-0.1.68.tar.gz:

Publisher: release.yaml on sophos/sophos-firewall-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sophosfirewall_python-0.1.68-py3-none-any.whl.

File metadata

File hashes

Hashes for sophosfirewall_python-0.1.68-py3-none-any.whl
Algorithm Hash digest
SHA256 cb250afef0f7d9ba1b4046ecd72658da197209c4c9ce9d7da43bd82272984d6a
MD5 6edc535965351a3a1e0fca5449e2d454
BLAKE2b-256 a746fbadfb60e674730c03db7460b31e538318cb6f808a5cf022d3953262596f

See more details on using hashes here.

Provenance

The following attestation bundles were made for sophosfirewall_python-0.1.68-py3-none-any.whl:

Publisher: release.yaml on sophos/sophos-firewall-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.68 This release

2 files

0.1.67

2 files

0.1.66

2 files

0.1.65

2 files

0.1.64

2 files

0.1.63

2 files

0.1.62

2 files

0.1.61

2 files

0.1.60

2 files

0.1.59

2 files

0.1.58

2 files

0.1.57

2 files

0.1.56

2 files

0.1.55

2 files

0.1.54

2 files

0.1.53

2 files

0.1.52

2 files

0.1.51

2 files

0.1.50

2 files

0.1.49

2 files

0.1.48

2 files

0.1.47

2 files

0.1.46

2 files

0.1.45

2 files

0.1.44

2 files

0.1.43

2 files

0.1.42

2 files

0.1.41

2 files

0.1.40

2 files

0.1.39

2 files

0.1.38

2 files

0.1.37

2 files

0.1.36

2 files

0.1.35

2 files

0.1.34

2 files

0.1.33

2 files

0.1.32

2 files

0.1.31

2 files

0.1.29

2 files

0.1.28

2 files

0.1.27

2 files

0.1.26

2 files

0.1.25

2 files

0.1.24

2 files

0.1.23

2 files

0.1.22

2 files

0.1.21

2 files

0.1.19

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page