diff --git a/.github/workflows/client-test.yml b/.github/workflows/client-test.yml new file mode 100644 index 0000000..72dd430 --- /dev/null +++ b/.github/workflows/client-test.yml @@ -0,0 +1,74 @@ +name: '๐Ÿงช Test Cloud Client' + +on: + push: + branches: + - 'main' + paths: + - '*.py' + - '.github/workflows/*.yml' + - '.github/workflows/*.json' + - '!**/README.md' + + pull_request: + types: + - opened + - edited + - reopened + - synchronize + branches: + - 'main' + paths: + - '*.py' + - '.github/workflows/*.yml' + - '.github/workflows/*.json' + - '!**/README.md' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: 'โณ Checkout repository' + uses: actions/checkout@v3 + + - name: '๐Ÿ Set up Python' + uses: actions/setup-python@v4 + with: + cache: 'pip' + python-version: "3.10" + + - name: '๐Ÿ›  Install dependencies' + run: | + python -m pip install --upgrade pip + python -m pip install build==0.10.0 cbor2==5.4.6 M2Crypto==0.38.0 micropython-senml==0.1.0 + sudo apt-get install openssl softhsm2 gnutls-bin libengine-pkcs11-openssl + + - name: '๐Ÿ“ฆ Build package' + run: python3 -m build + + - name: '๐Ÿ›  Install package' + run: | + python3 -m build + pip install dist/arduino_iot_cloud-*.whl + + - name: '๐Ÿ”‘ Configure soft crypto device' + env: + KEY_PEM: ${{ secrets.KEY_PEM }} + CERT_PEM: ${{ secrets.CERT_PEM }} + CA_PEM: ${{ secrets.CA_PEM }} + run: | + source tests/ci.sh && ci_configure_softhsm + + - name: 'โ˜๏ธ Connect to IoT cloud (basic auth)' + env: + DEVICE_ID: ${{ secrets.DEVICE_ID1 }} + SECRET_KEY: ${{ secrets.SECRET_KEY }} + run: | + python tests/ci.py + + - name: 'โ˜๏ธ Connect to IoT cloud (using crypto device)' + env: + DEVICE_ID: ${{ secrets.DEVICE_ID2 }} + SECRET_KEY: ${{ secrets.SECRET_KEY }} + run: | + python tests/ci.py --crypto-device diff --git a/tests/ci.py b/tests/ci.py new file mode 100644 index 0000000..913a495 --- /dev/null +++ b/tests/ci.py @@ -0,0 +1,76 @@ +# This file is part of the Python Arduino IoT Cloud. +# Any copyright is dedicated to the Public Domain. +# https://creativecommons.org/publicdomain/zero/1.0/ +import logging +import os +import sys +import asyncio +from arduino_iot_cloud import ArduinoCloudClient +import argparse +import arduino_iot_cloud.ussl as ssl + + +def exception_handler(loop, context): + pass + + +def on_value_changed(client, value): + logging.info(f"The answer to life, the universe, and everything is {value}") + loop = asyncio.get_event_loop() + loop.set_exception_handler(exception_handler) + sys.exit(0) + + +if __name__ == "__main__": + # Parse command line args. + parser = argparse.ArgumentParser(description="arduino_iot_cloud.py") + parser.add_argument( + "-d", "--debug", action="store_true", help="Enable debugging messages" + ) + parser.add_argument( + "-c", "--crypto-device", action="store_true", help="Use crypto device" + ) + args = parser.parse_args() + + # Configure the logger. + # All message equal or higher to the logger level are printed. + # To see more debugging messages, pass --debug on the command line. + logging.basicConfig( + datefmt="%H:%M:%S", + format="%(asctime)s.%(msecs)03d %(message)s", + level=logging.DEBUG if args.debug else logging.INFO, + ) + + # Create a client object to connect to the Arduino IoT cloud. + # To use a secure element, set the token's "pin" and URI in "keyfile" and "certfile", and + # the CA certificate (if any) in "ssl_params". Alternatively, a username and password can + # be used to authenticate, for example: + # client = ArduinoCloudClient(device_id=DEVICE_ID, username=DEVICE_ID, password=SECRET_KEY) + if args.crypto_device: + client = ArduinoCloudClient( + device_id=os.environ["DEVICE_ID"], + ssl_params={ + "pin": "1234", + "keyfile": "pkcs11:token=arduino", + "certfile": "pkcs11:token=arduino", + "ca_certs": "ca-root.pem", + "cert_reqs": ssl.CERT_REQUIRED, + "engine_path": "/usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so", + "module_path": "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", + }, + ) + else: + client = ArduinoCloudClient( + device_id=os.environ["DEVICE_ID"], + username=os.environ["DEVICE_ID"], + password=os.environ["SECRET_KEY"], + ) + + # Register cloud objects. + # Note: The following objects must be created first in the dashboard and linked to the device. + # This cloud object is initialized with its last known value from the cloud. When this object is updated + # from the dashboard, the on_switch_changed function is called with the client object and the new value. + client.register("answer", value=None, on_write=on_value_changed) + + # Start the Arduino IoT cloud client. + client.start() diff --git a/tests/ci.sh b/tests/ci.sh new file mode 100755 index 0000000..f885040 --- /dev/null +++ b/tests/ci.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +ci_configure_softhsm() { +TOKEN="pkcs11:token=arduino" +PROVIDER=/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so + +echo "$KEY_PEM" >> key.pem +echo "$CERT_PEM" >> cert.pem +echo "$CA_PEM" >> ca-root.pem + +#mkdir -p ${HOME}/softhsm/tokens/ +#sudo tee </dev/null +#directories.tokendir = ${HOME}/softhsm/tokens/ +#objectstore.backend = file +# +## ERROR, WARNING, INFO, DEBUG +#log.level = ERROR +# +## If CKF_REMOVABLE_DEVICE flag should be set +#slots.removable = false +# +## Enable and disable PKCS#11 mechanisms using slots.mechanisms. +#slots.mechanisms = ALL +# +## If the library should reset the state on fork +#library.reset_on_fork = false +#EOF + +sudo softhsm2-util --init-token --slot 0 --label "arduino" --pin 1234 --so-pin 1234 +sudo p11tool --provider=${PROVIDER} --login --set-pin=1234 --write ${TOKEN} --load-privkey key.pem --label "mykey" +sudo p11tool --provider=${PROVIDER} --login --set-pin=1234 --write ${TOKEN} --load-certificate cert.pem --label "mycert" +}