├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── package.yml │ ├── scorecard.yml │ └── testing.yml ├── .gitignore ├── .pylintrc ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bin └── testrun ├── cmd ├── build ├── build_ui ├── install ├── package ├── prepare ├── prune └── update_requirements ├── docs ├── README.md ├── additional_config.md ├── dev │ ├── README.md │ ├── architecture.png │ ├── mockoon.json │ └── postman.json ├── get_started.md ├── network │ ├── README.md │ ├── add_new_service.md │ └── addresses.md ├── roadmap.pdf ├── setup │ ├── install.gif │ └── visual.png ├── test │ ├── README.md │ ├── modules.md │ └── statuses.md ├── ui │ ├── accessibility.md │ ├── accessibility.mp4 │ ├── getstarted--2dn8vrzsspe.png │ ├── getstarted--3d9k3si3ul1.png │ ├── getstarted-actions-device.png │ ├── getstarted-actions-testing.png │ ├── getstarted-add-device.png │ ├── getstarted-certificates-menu.png │ ├── getstarted-device-repository.png │ ├── getstarted-reports.png │ ├── getstarted-risk-assessment.png │ ├── getstarted-settings-menu.png │ ├── getstarted-testing.png │ └── getstarted-waiting-for-device.png └── virtual_machine.md ├── framework ├── python │ └── src │ │ ├── api │ │ └── api.py │ │ ├── common │ │ ├── device.py │ │ ├── docker_util.py │ │ ├── logger.py │ │ ├── mqtt.py │ │ ├── risk_profile.py │ │ ├── statuses.py │ │ ├── tasks.py │ │ ├── testreport.py │ │ └── util.py │ │ ├── core │ │ ├── docker │ │ │ ├── docker_module.py │ │ │ ├── network_docker_module.py │ │ │ └── test_docker_module.py │ │ ├── session.py │ │ ├── tasks.py │ │ ├── test_runner.py │ │ └── testrun.py │ │ ├── net_orc │ │ ├── ip_control.py │ │ ├── listener.py │ │ ├── network_event.py │ │ ├── network_orchestrator.py │ │ ├── network_validator.py │ │ └── ovs_control.py │ │ └── test_orc │ │ ├── module.py │ │ ├── runner.py │ │ ├── test_case.py │ │ ├── test_orchestrator.py │ │ └── test_pack.py └── requirements.txt ├── local ├── .gitignore └── system.json.example ├── make ├── .gitignore └── DEBIAN │ ├── control │ ├── postrm │ └── prerm ├── modules ├── devices │ └── faux-dev │ │ ├── bin │ │ ├── get_default_gateway │ │ ├── start_dhcp_client │ │ └── start_network_service │ │ ├── conf │ │ └── module_config.json │ │ ├── faux-dev.Dockerfile │ │ └── python │ │ └── src │ │ ├── dhcp_check.py │ │ ├── dns_check.py │ │ ├── gateway_check.py │ │ ├── ntp_check.py │ │ └── run.py ├── network │ ├── base │ │ ├── base.Dockerfile │ │ ├── bin │ │ │ ├── capture │ │ │ ├── setup_binaries │ │ │ ├── setup_python_path │ │ │ ├── start_grpc │ │ │ ├── start_module │ │ │ ├── start_network_service │ │ │ └── wait_for_interface │ │ ├── conf │ │ │ └── module_config.json │ │ └── python │ │ │ ├── requirements.txt │ │ │ └── src │ │ │ ├── grpc_server │ │ │ └── start_server.py │ │ │ └── logger.py │ ├── dhcp-1 │ │ ├── bin │ │ │ ├── isc-dhcp-service │ │ │ ├── radvd-service │ │ │ └── start_network_service │ │ ├── conf │ │ │ ├── dhcpd.conf │ │ │ ├── isc-dhcp-server │ │ │ ├── module_config.json │ │ │ └── radvd.conf │ │ ├── dhcp-1.Dockerfile │ │ └── python │ │ │ └── src │ │ │ └── grpc_server │ │ │ ├── __init__.py │ │ │ ├── dhcp_config.py │ │ │ ├── dhcp_config_test.py │ │ │ ├── dhcp_lease.py │ │ │ ├── dhcp_leases.py │ │ │ ├── dhcp_server.py │ │ │ ├── isc_dhcp_server.py │ │ │ ├── network_service.py │ │ │ ├── proto │ │ │ └── grpc.proto │ │ │ └── radvd_server.py │ ├── dhcp-2 │ │ ├── bin │ │ │ ├── isc-dhcp-service │ │ │ ├── radvd-service │ │ │ └── start_network_service │ │ ├── conf │ │ │ ├── dhcpd.conf │ │ │ ├── isc-dhcp-server │ │ │ ├── module_config.json │ │ │ └── radvd.conf │ │ ├── dhcp-2.Dockerfile │ │ └── python │ │ │ └── src │ │ │ └── grpc_server │ │ │ ├── __init__.py │ │ │ ├── dhcp_config.py │ │ │ ├── dhcp_config_test.py │ │ │ ├── dhcp_lease.py │ │ │ ├── dhcp_leases.py │ │ │ ├── dhcp_server.py │ │ │ ├── isc_dhcp_server.py │ │ │ ├── network_service.py │ │ │ ├── proto │ │ │ └── grpc.proto │ │ │ └── radvd_server.py │ ├── dns │ │ ├── bin │ │ │ └── start_network_service │ │ ├── conf │ │ │ ├── dnsmasq.conf │ │ │ └── module_config.json │ │ └── dns.Dockerfile │ ├── gateway │ │ ├── bin │ │ │ └── start_network_service │ │ ├── conf │ │ │ └── module_config.json │ │ └── gateway.Dockerfile │ ├── host │ │ ├── bin │ │ │ └── start_network_service │ │ ├── conf │ │ │ └── module_config.json │ │ ├── host.Dockerfile │ │ └── python │ │ │ └── src │ │ │ └── grpc_server │ │ │ ├── network_service.py │ │ │ ├── proto │ │ │ └── grpc.proto │ │ │ └── start_server.py │ ├── ntp │ │ ├── bin │ │ │ └── start_network_service │ │ ├── conf │ │ │ ├── chrony.conf │ │ │ └── module_config.json │ │ ├── ntp.Dockerfile │ │ └── python │ │ │ └── src │ │ │ ├── chronyd.py │ │ │ └── ntp_server.py │ ├── radius │ │ ├── bin │ │ │ └── start_network_service │ │ ├── conf │ │ │ ├── ca.crt │ │ │ ├── eap │ │ │ └── module_config.json │ │ ├── python │ │ │ ├── requirements.txt │ │ │ └── src │ │ │ │ └── authenticator.py │ │ └── radius.Dockerfile │ └── template │ │ ├── bin │ │ └── start_network_service │ │ ├── conf │ │ └── module_config.json │ │ ├── python │ │ └── src │ │ │ └── template_main.py │ │ └── template.Dockerfile ├── test │ ├── base │ │ ├── README.md │ │ ├── base.Dockerfile │ │ ├── bin │ │ │ ├── capture │ │ │ ├── get_ipv4_addr │ │ │ ├── setup │ │ │ ├── setup_binaries │ │ │ ├── setup_grpc_clients │ │ │ ├── setup_python_path │ │ │ ├── start │ │ │ ├── start_grpc │ │ │ ├── start_module │ │ │ └── wait_for_interface │ │ ├── conf │ │ │ └── module_config.json │ │ ├── python │ │ │ ├── requirements.txt │ │ │ └── src │ │ │ │ ├── grpc │ │ │ │ ├── proto │ │ │ │ │ ├── dhcp1 │ │ │ │ │ │ └── client.py │ │ │ │ │ ├── dhcp2 │ │ │ │ │ │ └── client.py │ │ │ │ │ └── host │ │ │ │ │ │ └── client.py │ │ │ │ └── start_server.py │ │ │ │ └── test_module.py │ │ └── usr │ │ │ └── local │ │ │ └── etc │ │ │ └── oui.txt │ ├── baseline │ │ ├── README.md │ │ ├── baseline.Dockerfile │ │ ├── bin │ │ │ └── start_test_module │ │ ├── conf │ │ │ └── module_config.json │ │ └── python │ │ │ └── src │ │ │ ├── baseline_module.py │ │ │ └── run.py │ ├── conn │ │ ├── README.md │ │ ├── bin │ │ │ ├── get_packet_counts.sh │ │ │ └── start_test_module │ │ ├── conf │ │ │ └── module_config.json │ │ ├── conn.Dockerfile │ │ └── python │ │ │ ├── requirements.txt │ │ │ └── src │ │ │ ├── connection_module.py │ │ │ ├── dhcp_util.py │ │ │ ├── port_stats_util.py │ │ │ └── run.py │ ├── dns │ │ ├── README.md │ │ ├── bin │ │ │ └── start_test_module │ │ ├── conf │ │ │ └── module_config.json │ │ ├── dns.Dockerfile │ │ ├── python │ │ │ ├── requirements.txt │ │ │ └── src │ │ │ │ ├── dns_module.py │ │ │ │ └── run.py │ │ └── resources │ │ │ └── report_template.jinja2 │ ├── ntp │ │ ├── README.md │ │ ├── bin │ │ │ └── start_test_module │ │ ├── conf │ │ │ └── module_config.json │ │ ├── ntp.Dockerfile │ │ ├── python │ │ │ ├── requirements.txt │ │ │ └── src │ │ │ │ ├── ntp_module.py │ │ │ │ └── run.py │ │ └── resources │ │ │ └── report_template.jinja2 │ ├── protocol │ │ ├── README.md │ │ ├── bin │ │ │ ├── get_bacnet_packets.sh │ │ │ └── start_test_module │ │ ├── conf │ │ │ └── module_config.json │ │ ├── protocol.Dockerfile │ │ └── python │ │ │ ├── requirements.txt │ │ │ └── src │ │ │ ├── protocol_bacnet.py │ │ │ ├── protocol_modbus.py │ │ │ ├── protocol_module.py │ │ │ └── run.py │ ├── services │ │ ├── README.md │ │ ├── bin │ │ │ └── start_test_module │ │ ├── conf │ │ │ └── module_config.json │ │ ├── python │ │ │ ├── requirements.txt │ │ │ └── src │ │ │ │ ├── run.py │ │ │ │ └── services_module.py │ │ ├── resources │ │ │ └── report_template.jinja2 │ │ └── services.Dockerfile │ └── tls │ │ ├── README.md │ │ ├── bin │ │ ├── check_cert_chain_signature.sh │ │ ├── check_cert_signature.sh │ │ ├── get_ciphers.sh │ │ ├── get_client_hello_packets.sh │ │ ├── get_handshake_complete.sh │ │ ├── get_non_tls_client_connections.sh │ │ ├── get_tls_client_connections.sh │ │ ├── get_tls_packets.sh │ │ └── start_test_module │ │ ├── conf │ │ └── module_config.json │ │ ├── python │ │ ├── requirements-test.txt │ │ ├── requirements.txt │ │ └── src │ │ │ ├── http_scan.py │ │ │ ├── run.py │ │ │ ├── tls_module.py │ │ │ └── tls_util.py │ │ ├── resources │ │ └── report_template.jinja2 │ │ └── tls.Dockerfile ├── ui │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc.json │ ├── README.md │ ├── angular.json │ ├── build.Dockerfile │ ├── karma.conf.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── app-routing.module.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.store.spec.ts │ │ │ ├── app.store.ts │ │ │ ├── components │ │ │ │ ├── bypass │ │ │ │ │ ├── bypass.component.html │ │ │ │ │ ├── bypass.component.scss │ │ │ │ │ ├── bypass.component.spec.ts │ │ │ │ │ └── bypass.component.ts │ │ │ │ ├── callout │ │ │ │ │ ├── callout.component.html │ │ │ │ │ ├── callout.component.scss │ │ │ │ │ ├── callout.component.spec.ts │ │ │ │ │ └── callout.component.ts │ │ │ │ ├── component-with-announcement.ts │ │ │ │ ├── device-item │ │ │ │ │ ├── device-item.component.html │ │ │ │ │ ├── device-item.component.scss │ │ │ │ │ ├── device-item.component.spec.ts │ │ │ │ │ └── device-item.component.ts │ │ │ │ ├── device-tests │ │ │ │ │ ├── device-tests.component.html │ │ │ │ │ ├── device-tests.component.scss │ │ │ │ │ ├── device-tests.component.spec.ts │ │ │ │ │ └── device-tests.component.ts │ │ │ │ ├── download-report-pdf │ │ │ │ │ ├── download-report-pdf.component.html │ │ │ │ │ ├── download-report-pdf.component.spec.ts │ │ │ │ │ └── download-report-pdf.component.ts │ │ │ │ ├── download-report-zip │ │ │ │ │ ├── download-report-zip.component.html │ │ │ │ │ ├── download-report-zip.component.scss │ │ │ │ │ ├── download-report-zip.component.spec.ts │ │ │ │ │ └── download-report-zip.component.ts │ │ │ │ ├── download-report │ │ │ │ │ ├── download-report.component.html │ │ │ │ │ ├── download-report.component.scss │ │ │ │ │ ├── download-report.component.spec.ts │ │ │ │ │ └── download-report.component.ts │ │ │ │ ├── download-zip-modal │ │ │ │ │ ├── download-zip-modal.component.html │ │ │ │ │ ├── download-zip-modal.component.scss │ │ │ │ │ ├── download-zip-modal.component.spec.ts │ │ │ │ │ └── download-zip-modal.component.ts │ │ │ │ ├── dynamic-form │ │ │ │ │ ├── dynamic-form.component.html │ │ │ │ │ ├── dynamic-form.component.scss │ │ │ │ │ ├── dynamic-form.component.spec.ts │ │ │ │ │ └── dynamic-form.component.ts │ │ │ │ ├── empty-message │ │ │ │ │ ├── empty-message.component.html │ │ │ │ │ ├── empty-message.component.scss │ │ │ │ │ ├── empty-message.component.spec.ts │ │ │ │ │ └── empty-message.component.ts │ │ │ │ ├── empty-page │ │ │ │ │ ├── empty-page.component.html │ │ │ │ │ ├── empty-page.component.spec.ts │ │ │ │ │ └── empty-page.component.ts │ │ │ │ ├── escapable-dialog │ │ │ │ │ ├── escapable-dialog.component.spec.ts │ │ │ │ │ └── escapable-dialog.component.ts │ │ │ │ ├── help-tip │ │ │ │ │ ├── help-tip.component.html │ │ │ │ │ ├── help-tip.component.scss │ │ │ │ │ ├── help-tip.component.spec.ts │ │ │ │ │ └── help-tip.component.ts │ │ │ │ ├── list-item │ │ │ │ │ ├── list-item.component.html │ │ │ │ │ ├── list-item.component.scss │ │ │ │ │ ├── list-item.component.spec.ts │ │ │ │ │ └── list-item.component.ts │ │ │ │ ├── list-layout │ │ │ │ │ ├── list-layout.component.html │ │ │ │ │ ├── list-layout.component.scss │ │ │ │ │ ├── list-layout.component.spec.ts │ │ │ │ │ └── list-layout.component.ts │ │ │ │ ├── no-entity-selected │ │ │ │ │ ├── no-entity-selected.component.html │ │ │ │ │ ├── no-entity-selected.component.scss │ │ │ │ │ └── no-entity-selected.component.ts │ │ │ │ ├── program-type-icon │ │ │ │ │ ├── program-type-con.component.spec.ts │ │ │ │ │ └── program-type-icon.component.ts │ │ │ │ ├── report-action │ │ │ │ │ ├── report-action.component.spec.ts │ │ │ │ │ └── report-action.component.ts │ │ │ │ ├── shutdown-app │ │ │ │ │ ├── shutdown-app.component.html │ │ │ │ │ ├── shutdown-app.component.spec.ts │ │ │ │ │ └── shutdown-app.component.ts │ │ │ │ ├── side-button-menu │ │ │ │ │ ├── side-button-menu.component.html │ │ │ │ │ ├── side-button-menu.component.scss │ │ │ │ │ ├── side-button-menu.component.spec.ts │ │ │ │ │ └── side-button-menu.component.ts │ │ │ │ ├── simple-dialog │ │ │ │ │ ├── simple-dialog.component.html │ │ │ │ │ ├── simple-dialog.component.scss │ │ │ │ │ ├── simple-dialog.component.spec.ts │ │ │ │ │ └── simple-dialog.component.ts │ │ │ │ ├── snack-bar │ │ │ │ │ ├── snack-bar.component.html │ │ │ │ │ ├── snack-bar.component.scss │ │ │ │ │ ├── snack-bar.component.spec.ts │ │ │ │ │ └── snack-bar.component.ts │ │ │ │ ├── spinner │ │ │ │ │ ├── spinner.component.html │ │ │ │ │ ├── spinner.component.scss │ │ │ │ │ ├── spinner.component.spec.ts │ │ │ │ │ └── spinner.component.ts │ │ │ │ ├── stepper │ │ │ │ │ ├── stepper-test.component.html │ │ │ │ │ ├── stepper.component.html │ │ │ │ │ ├── stepper.component.scss │ │ │ │ │ ├── stepper.component.spec.ts │ │ │ │ │ └── stepper.component.ts │ │ │ │ ├── testing-complete │ │ │ │ │ ├── testing-complete.component.spec.ts │ │ │ │ │ └── testing-complete.component.ts │ │ │ │ ├── version │ │ │ │ │ ├── consent-dialog │ │ │ │ │ │ ├── consent-dialog.component.html │ │ │ │ │ │ ├── consent-dialog.component.scss │ │ │ │ │ │ ├── consent-dialog.component.spec.ts │ │ │ │ │ │ └── consent-dialog.component.ts │ │ │ │ │ ├── version.component.html │ │ │ │ │ ├── version.component.scss │ │ │ │ │ ├── version.component.spec.ts │ │ │ │ │ └── version.component.ts │ │ │ │ └── wifi │ │ │ │ │ ├── wifi.component.html │ │ │ │ │ ├── wifi.component.spec.ts │ │ │ │ │ └── wifi.component.ts │ │ │ ├── guards │ │ │ │ ├── can-activate.guard.spec.ts │ │ │ │ ├── can-activate.guard.ts │ │ │ │ ├── can-deactivate.guard.spec.ts │ │ │ │ └── can-deactivate.guard.ts │ │ │ ├── interceptors │ │ │ │ ├── error-handler.interceptor.spec.ts │ │ │ │ ├── error-handler.interceptor.ts │ │ │ │ ├── error.interceptor.spec.ts │ │ │ │ ├── error.interceptor.ts │ │ │ │ ├── loading.interceptor.spec.ts │ │ │ │ └── loading.interceptor.ts │ │ │ ├── mocks │ │ │ │ ├── certificate.mock.ts │ │ │ │ ├── device.mock.ts │ │ │ │ ├── profile.mock.ts │ │ │ │ ├── reports.mock.ts │ │ │ │ ├── settings.mock.ts │ │ │ │ ├── testrun.mock.ts │ │ │ │ ├── topic.mock.ts │ │ │ │ └── version.mock.ts │ │ │ ├── model │ │ │ │ ├── callout-type.ts │ │ │ │ ├── certificate.ts │ │ │ │ ├── device.ts │ │ │ │ ├── entity-action.ts │ │ │ │ ├── event-type.ts │ │ │ │ ├── filters.ts │ │ │ │ ├── layout-type.ts │ │ │ │ ├── profile.ts │ │ │ │ ├── program-type.ts │ │ │ │ ├── question.ts │ │ │ │ ├── routes.ts │ │ │ │ ├── setting.ts │ │ │ │ ├── testrun-status.ts │ │ │ │ ├── tip-config.ts │ │ │ │ ├── topic.ts │ │ │ │ └── version.ts │ │ │ ├── pages │ │ │ │ ├── certificates │ │ │ │ │ ├── certificate.validator.ts │ │ │ │ │ ├── certificates.component.html │ │ │ │ │ ├── certificates.component.scss │ │ │ │ │ ├── certificates.component.spec.ts │ │ │ │ │ ├── certificates.component.ts │ │ │ │ │ ├── certificates.store.spec.ts │ │ │ │ │ ├── certificates.store.ts │ │ │ │ │ └── components │ │ │ │ │ │ ├── certificate-upload-button │ │ │ │ │ │ ├── certificate-upload-button.component.html │ │ │ │ │ │ ├── certificate-upload-button.component.scss │ │ │ │ │ │ ├── certificate-upload-button.component.spec.ts │ │ │ │ │ │ └── certificate-upload-button.component.ts │ │ │ │ │ │ └── certificates-table │ │ │ │ │ │ ├── certificates-table.component.html │ │ │ │ │ │ ├── certificates-table.component.scss │ │ │ │ │ │ ├── certificates-table.component.spec.ts │ │ │ │ │ │ └── certificates-table.component.ts │ │ │ │ ├── devices │ │ │ │ │ ├── components │ │ │ │ │ │ ├── device-form │ │ │ │ │ │ │ └── device.validators.ts │ │ │ │ │ │ └── device-qualification-from │ │ │ │ │ │ │ ├── device-qualification-from.component.html │ │ │ │ │ │ │ ├── device-qualification-from.component.scss │ │ │ │ │ │ │ ├── device-qualification-from.component.spec.ts │ │ │ │ │ │ │ └── device-qualification-from.component.ts │ │ │ │ │ ├── devices.component.html │ │ │ │ │ ├── devices.component.scss │ │ │ │ │ ├── devices.component.spec.ts │ │ │ │ │ ├── devices.component.ts │ │ │ │ │ ├── devices.store.spec.ts │ │ │ │ │ └── devices.store.ts │ │ │ │ ├── general-settings │ │ │ │ │ ├── components │ │ │ │ │ │ └── settings-dropdown │ │ │ │ │ │ │ ├── settings-dropdown.component.html │ │ │ │ │ │ │ ├── settings-dropdown.component.scss │ │ │ │ │ │ │ ├── settings-dropdown.component.spec.ts │ │ │ │ │ │ │ └── settings-dropdown.component.ts │ │ │ │ │ ├── general-settings.component.html │ │ │ │ │ ├── general-settings.component.scss │ │ │ │ │ ├── general-settings.component.spec.ts │ │ │ │ │ ├── general-settings.component.ts │ │ │ │ │ ├── general-settings.store.spec.ts │ │ │ │ │ ├── general-settings.store.ts │ │ │ │ │ └── only-different-values.validator.ts │ │ │ │ ├── reports │ │ │ │ │ ├── components │ │ │ │ │ │ ├── delete-report │ │ │ │ │ │ │ ├── delete-report.component.html │ │ │ │ │ │ │ ├── delete-report.component.scss │ │ │ │ │ │ │ ├── delete-report.component.spec.ts │ │ │ │ │ │ │ └── delete-report.component.ts │ │ │ │ │ │ ├── filter-chips │ │ │ │ │ │ │ ├── filter-chips.component.html │ │ │ │ │ │ │ ├── filter-chips.component.scss │ │ │ │ │ │ │ ├── filter-chips.component.spec.ts │ │ │ │ │ │ │ └── filter-chips.component.ts │ │ │ │ │ │ ├── filter-dialog │ │ │ │ │ │ │ ├── filter-dialog.component.html │ │ │ │ │ │ │ ├── filter-dialog.component.scss │ │ │ │ │ │ │ ├── filter-dialog.component.spec.ts │ │ │ │ │ │ │ └── filter-dialog.component.ts │ │ │ │ │ │ └── filter-header │ │ │ │ │ │ │ ├── filter-header.component.html │ │ │ │ │ │ │ ├── filter-header.component.scss │ │ │ │ │ │ │ ├── filter-header.component.spec.ts │ │ │ │ │ │ │ └── filter-header.component.ts │ │ │ │ │ ├── reports.component.html │ │ │ │ │ ├── reports.component.scss │ │ │ │ │ ├── reports.component.spec.ts │ │ │ │ │ ├── reports.component.ts │ │ │ │ │ ├── reports.store.spec.ts │ │ │ │ │ └── reports.store.ts │ │ │ │ ├── risk-assessment │ │ │ │ │ ├── components │ │ │ │ │ │ └── success-dialog │ │ │ │ │ │ │ ├── success-dialog.component.html │ │ │ │ │ │ │ ├── success-dialog.component.scss │ │ │ │ │ │ │ ├── success-dialog.component.spec.ts │ │ │ │ │ │ │ └── success-dialog.component.ts │ │ │ │ │ ├── profile-form │ │ │ │ │ │ ├── profile-form.component.html │ │ │ │ │ │ ├── profile-form.component.scss │ │ │ │ │ │ ├── profile-form.component.spec.ts │ │ │ │ │ │ ├── profile-form.component.ts │ │ │ │ │ │ └── profile.validators.ts │ │ │ │ │ ├── profile-item │ │ │ │ │ │ ├── profile-item.component.html │ │ │ │ │ │ ├── profile-item.component.scss │ │ │ │ │ │ ├── profile-item.component.spec.ts │ │ │ │ │ │ └── profile-item.component.ts │ │ │ │ │ ├── risk-assessment.component.html │ │ │ │ │ ├── risk-assessment.component.scss │ │ │ │ │ ├── risk-assessment.component.spec.ts │ │ │ │ │ ├── risk-assessment.component.ts │ │ │ │ │ ├── risk-assessment.store.spec.ts │ │ │ │ │ └── risk-assessment.store.ts │ │ │ │ ├── settings │ │ │ │ │ ├── settings.component.html │ │ │ │ │ ├── settings.component.scss │ │ │ │ │ ├── settings.component.spec.ts │ │ │ │ │ └── settings.component.ts │ │ │ │ └── testrun │ │ │ │ │ ├── components │ │ │ │ │ ├── download-options │ │ │ │ │ │ ├── download-options.component.html │ │ │ │ │ │ ├── download-options.component.scss │ │ │ │ │ │ ├── download-options.component.spec.ts │ │ │ │ │ │ └── download-options.component.ts │ │ │ │ │ ├── test-result-dialog │ │ │ │ │ │ ├── test-result-dialog.component.html │ │ │ │ │ │ ├── test-result-dialog.component.scss │ │ │ │ │ │ ├── test-result-dialog.component.spec.ts │ │ │ │ │ │ └── test-result-dialog.component.ts │ │ │ │ │ ├── testrun-initiate-form │ │ │ │ │ │ ├── testrun-initiate-form.component.html │ │ │ │ │ │ ├── testrun-initiate-form.component.scss │ │ │ │ │ │ ├── testrun-initiate-form.component.spec.ts │ │ │ │ │ │ └── testrun-initiate-form.component.ts │ │ │ │ │ ├── testrun-status-card │ │ │ │ │ │ ├── testrun-status-card.component.html │ │ │ │ │ │ ├── testrun-status-card.component.scss │ │ │ │ │ │ ├── testrun-status-card.component.spec.ts │ │ │ │ │ │ └── testrun-status-card.component.ts │ │ │ │ │ └── testrun-table │ │ │ │ │ │ ├── testrun-table.component.html │ │ │ │ │ │ ├── testrun-table.component.scss │ │ │ │ │ │ ├── testrun-table.component.spec.ts │ │ │ │ │ │ └── testrun-table.component.ts │ │ │ │ │ ├── testrun.component.html │ │ │ │ │ ├── testrun.component.scss │ │ │ │ │ ├── testrun.component.spec.ts │ │ │ │ │ ├── testrun.component.ts │ │ │ │ │ ├── testrun.store.spec.ts │ │ │ │ │ └── testrun.store.ts │ │ │ ├── providers │ │ │ │ └── window.provider.ts │ │ │ ├── services │ │ │ │ ├── focus-manager.service.spec.ts │ │ │ │ ├── focus-manager.service.ts │ │ │ │ ├── loader.service.spec.ts │ │ │ │ ├── loader.service.ts │ │ │ │ ├── loaderConfig.ts │ │ │ │ ├── local-storage.service.spec.ts │ │ │ │ ├── local-storage.service.ts │ │ │ │ ├── notification.service.spec.ts │ │ │ │ ├── notification.service.ts │ │ │ │ ├── test-run-mqtt.service.spec.ts │ │ │ │ ├── test-run-mqtt.service.ts │ │ │ │ ├── test-run.service.spec.ts │ │ │ │ └── test-run.service.ts │ │ │ └── store │ │ │ │ ├── actions.ts │ │ │ │ ├── effects.spec.ts │ │ │ │ ├── effects.ts │ │ │ │ ├── reducers.spec.ts │ │ │ │ ├── reducers.ts │ │ │ │ ├── selectors.spec.ts │ │ │ │ ├── selectors.ts │ │ │ │ └── state.ts │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── icons │ │ │ │ ├── close.svg │ │ │ │ ├── cornerstone.svg │ │ │ │ ├── create_device_header.svg │ │ │ │ ├── desktop-new.svg │ │ │ │ ├── desktop.svg │ │ │ │ ├── device_run.svg │ │ │ │ ├── devices_add.svg │ │ │ │ ├── dog.svg │ │ │ │ ├── draft.svg │ │ │ │ ├── empty-devices.svg │ │ │ │ ├── empty-profiles.svg │ │ │ │ ├── empty-testrun.svg │ │ │ │ ├── menu.svg │ │ │ │ ├── pilot.svg │ │ │ │ ├── qualification.svg │ │ │ │ ├── score.svg │ │ │ │ ├── switch.svg │ │ │ │ ├── testrun_logo.svg │ │ │ │ ├── testrun_logo_color.svg │ │ │ │ └── testrun_logo_small.svg │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── styles.scss │ │ └── theming │ │ │ ├── colors.scss │ │ │ ├── m3-theme.scss │ │ │ ├── mixins.scss │ │ │ └── variables.scss │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── ui.Dockerfile └── ws │ ├── conf │ └── mosquitto.conf │ └── ws.Dockerfile ├── resources ├── devices │ ├── device_profile.json │ └── template │ │ └── device_config.json ├── report │ ├── Google Sans.woff2 │ ├── module_report_base.jinja2 │ ├── risk_report_styles.css │ ├── risk_report_template.html │ ├── test_report_styles.css │ └── testrun.png ├── risk_assessment.json └── test_packs │ ├── pilot │ ├── config.json │ ├── report_templates │ │ ├── device_profile.jinja │ │ ├── header.jinja │ │ ├── icon.png │ │ ├── report_template.html │ │ ├── resolve_steps.jinja │ │ ├── results.jinja │ │ └── summary.jinja │ └── test_pack.py │ └── qualification │ ├── config.json │ ├── report_templates │ ├── device_profile.jinja │ ├── header.jinja │ ├── icon.png │ ├── report_template.html │ ├── resolve_steps.jinja │ ├── results.jinja │ └── summary.jinja │ └── test_pack.py └── testing ├── api ├── certificates │ ├── WR2.pem │ ├── crt.pem │ ├── invalid.pem │ └── invalidname1234567891234.pem ├── devices │ ├── device_1 │ │ └── device_config.json │ └── device_2 │ │ └── device_config.json ├── mockito │ ├── get_devices.json │ ├── invalid_request.json │ └── running_system_status.json ├── profiles │ ├── draft_profile.json │ ├── invalid_name.json │ └── valid_profile.json ├── reports │ ├── report.json │ └── report.pdf ├── sys_config │ ├── system.json │ └── updated_system.json ├── test_api └── test_api.py ├── baseline ├── system.json ├── test_baseline └── test_baseline.py ├── device_configs ├── bacnet_compliant │ └── device_config.json ├── dns_compliant │ └── device_config.json ├── dns_non_compliant │ └── device_config.json ├── ntp_compliant │ └── device_config.json ├── ntp_non_compliant │ └── device_config.json ├── only_baseline │ └── device_config.json ├── protocol_compliant │ └── device_config.json ├── services_compliant │ └── device_config.json └── services_non_compliant │ └── device_config.json ├── docker ├── ci_baseline │ ├── Dockerfile │ └── entrypoint.sh └── ci_test_device1 │ ├── Dockerfile │ ├── bacnet_compliant │ ├── Dockerfile │ ├── entrypoint.py │ └── entrypoint.sh │ ├── dns_compliant │ ├── Dockerfile │ └── entrypoint.sh │ ├── dns_non_compliant │ ├── Dockerfile │ └── entrypoint.sh │ ├── entrypoint.sh │ ├── ntp_compliant │ ├── Dockerfile │ └── entrypoint.sh │ ├── ntp_non_compliant │ ├── Dockerfile │ └── entrypoint.sh │ ├── protocol_compliant │ ├── Dockerfile │ ├── entrypoint.py │ └── entrypoint.sh │ ├── services_compliant │ ├── Dockerfile │ └── entrypoint.sh │ └── services_non_compliant │ ├── Dockerfile │ └── entrypoint.sh ├── example ├── mac └── mac1 │ └── results.json ├── pylint └── test_pylint ├── tests ├── example │ ├── mac │ └── mac1 │ │ └── results.json ├── system.json ├── test_tests ├── test_tests.json └── test_tests.py └── unit ├── conn ├── captures │ ├── monitor.pcap │ └── startup.pcap ├── conn_module_test.py ├── ethtool │ ├── ethtool_port_stats_post_monitor.txt │ ├── ethtool_port_stats_post_monitor_noncompliant.txt │ ├── ethtool_port_stats_pre_monitor.txt │ ├── ethtool_results_compliant.txt │ ├── ethtool_results_no_autononegotiation.txt │ └── ethtool_results_noncompliant.txt └── ifconfig │ ├── ifconfig_port_stats_post_monitor.txt │ ├── ifconfig_port_stats_post_noncompliant_monitor.txt │ └── ifconfig_port_stats_pre_monitor.txt ├── dns ├── captures │ ├── dns_dhcp_server │ │ ├── dns.pcap │ │ ├── monitor.pcap │ │ └── startup.pcap │ ├── dns_no_dns │ │ ├── dns.pcap │ │ ├── monitor.pcap │ │ └── startup.pcap │ └── dns_non_dhcp_server │ │ ├── dns.pcap │ │ ├── monitor.pcap │ │ └── startup.pcap ├── dns_module_test.py └── reports │ ├── dns_report_local.html │ └── dns_report_local_no_dns.html ├── framework ├── session_test.py └── util_test.py ├── ntp ├── captures │ ├── monitor.pcap │ ├── ntp.pcap │ └── startup.pcap ├── ntp_module_test.py └── reports │ ├── ntp_report_local.html │ └── ntp_report_local_no_ntp.html ├── protocol ├── captures │ └── bacnet.pcap └── protocol_module_test.py ├── report ├── pilot_do_not_proceed_noncompliant.json ├── pilot_proceed_compliant.json ├── pilot_proceed_noncompliant.json ├── qualification_compliant.json ├── qualification_noncompliant.json └── report_test.py ├── risk_profile ├── profiles │ ├── risk_profile_draft.json │ ├── risk_profile_expired.json │ ├── risk_profile_valid_high.json │ └── risk_profile_valid_limited.json └── risk_profile_test.py ├── run.sh ├── run_report_test.sh ├── run_test_module.sh ├── services ├── output │ ├── nmap_report_all_closed.html │ ├── nmap_report_ports_open.html │ ├── services_report.html │ └── services_scan_results.json ├── reports │ ├── services_report_all_closed_local.html │ └── services_report_local.html ├── results │ ├── all_closed_scan_result.json │ └── ports_open_scan_result.json └── services_module_test.py └── tls ├── CertAuth ├── TestRun_CA_Root.key ├── Testrun_CA_Root.crt ├── Testrun_CA_Root.csr ├── Testrun_CA_Root.srl ├── device_cert_local.crt ├── device_cert_local.csr ├── device_cert_local.key ├── generateCA.sh └── generateLocalCert.sh ├── captures ├── monitor.pcap ├── monitor_with_quic.pcap ├── multi_page_monitor.pcap ├── multi_page_startup.pcap ├── multi_page_tls.pcap ├── no_tls.pcap ├── tls.pcap ├── tls_ext.pcap └── unsupported_tls.pcap ├── certs ├── _.google.com.crt └── device_cert_local.crt ├── monitor.pcap ├── no_tls.pcap ├── reports ├── tls_report_ext_local.html ├── tls_report_local.html ├── tls_report_no_cert_local.html └── tls_report_single.html ├── root_certs └── Testrun_CA_Root.crt ├── tls_module_test.py └── unsupported_tls.pcap /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us identify and resolve bugs 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Error logs** 24 | If applicable, provide a log from https://gist.github.com/ 25 | 26 | **Environment (please provide the following information about your setup):** 27 | - OS: [e.g. Ubuntu] 28 | - Version [e.g. 22.04] 29 | - Additional hardware (network adapters) 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new feature or change request 4 | title: '' 5 | labels: request 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What is the problem your feature is trying to solve?** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you think would solve the problem** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | runtime/ 2 | venv/ 3 | .vscode/ 4 | error 5 | pylint.out 6 | __pycache__/ 7 | build/ 8 | 9 | # Ignore generated files from unit tests 10 | testing/unit_test/temp/ 11 | testing/unit/conn/output/ 12 | testing/unit/dns/output/ 13 | testing/unit/nmap/output/ 14 | testing/unit/ntp/output/ 15 | testing/unit/tls/output/ 16 | testing/unit/tls/tmp/ 17 | testing/unit/report/output/ 18 | testing/unit/risk_profile/output/ 19 | testing/unit/services/output/ 20 | 21 | # Ignore generated files from requirements generation 22 | *requirements_freeze.txt 23 | *unique_freeze.txt 24 | *requirements_gen.txt 25 | 26 | *.deb 27 | make/DEBIAN/postinst 28 | 29 | testrun.log 30 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. 4 | 5 | ## Before you begin 6 | 7 | ### Sign our Contributor License Agreement 8 | 9 | Contributions to this project must be accompanied by a 10 | [Contributor License Agreement](https://cla.developers.google.com/about) (CLA). 11 | You (or your employer) retain the copyright to your contribution; this simply 12 | gives us permission to use and redistribute your contributions as part of the 13 | project. 14 | 15 | If you or your current employer have already signed the Google CLA (even if it 16 | was for a different project), you probably don't need to do it again. 17 | 18 | Visit to see your current agreements or to 19 | sign a new one. 20 | 21 | ### Review our Community Guidelines 22 | 23 | This project follows 24 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 25 | 26 | ## Contribution process 27 | 28 | ### Code Reviews 29 | 30 | All submissions, including submissions by project members, require review. We 31 | use GitHub pull requests for this purpose. Consult 32 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 33 | information on using pull requests. 34 | -------------------------------------------------------------------------------- /cmd/build_ui: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Build the UI 18 | echo Building the ui builder 19 | 20 | # Build UI builder image 21 | if docker build -t testrun/build-ui -f modules/ui/build.Dockerfile . ; then 22 | echo Successully built the ui builder 23 | else 24 | echo An error occurred whilst building the ui builder 25 | exit 1 26 | fi 27 | 28 | # Check that the container is not already running 29 | docker kill tr-ui-build 2> /dev/null || true 30 | 31 | echo "Building the user interface" 32 | 33 | # Start build container and build the ui dist 34 | docker run --rm -v "$(pwd)"/modules/ui:/modules/ui testrun/build-ui /bin/sh -c "npm install && npm run build" 35 | 36 | # Kill the container (Should not be running anymore) 37 | docker kill tr-ui-build 2> /dev/null || true 38 | -------------------------------------------------------------------------------- /cmd/prepare: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Optional script to prepare your system for use with Testrun. 18 | # Installs system dependencies 19 | 20 | echo Installing system dependencies 21 | 22 | # Install system dependencies 23 | sudo apt-get update && sudo apt-get install openvswitch-common openvswitch-switch python3 libpangocairo-1.0-0 ethtool 24 | 25 | echo Finished installing system dependencies 26 | -------------------------------------------------------------------------------- /cmd/prune: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Stop any running containers 18 | echo Stopping any running containers 19 | running_containers=$(docker container ls -q --filter name=tr-*) 20 | if [ -n "$running_containers" ]; then 21 | docker container kill $running_containers 22 | else 23 | echo No containers were found running 24 | fi 25 | 26 | # Remove docker images 27 | echo Removing docker images 28 | docker_images=$(sudo docker images --filter=reference="testrun/*" -q) 29 | 30 | if [ -z "$docker_images" ]; then 31 | echo No docker images to delete 32 | else 33 | sudo docker rmi $docker_images 34 | fi 35 | 36 | # Remove docker networks 37 | echo Removing docker networks 38 | sudo docker network rm endev0 || true 39 | 40 | echo Successfully pruned Testrun resources 41 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Testrun logo 2 | 3 | # Contents 4 | 5 | - [Get started](/docs/get_started.md) 6 | - [Run on a virtual machine](/docs/virtual_machine.md) 7 | - [Network](/docs/network/README.md) 8 | - [Network addresses](/docs/network/addresses.md) 9 | - [Add a new network service](/docs/network/add_new_service.md) 10 | - [Testing](/docs/test/README.md) 11 | - [Test modules](/docs/test/modules.md) 12 | - [Test results](/docs/test/statuses.md) 13 | - [Developer guidelines](/docs/dev/README.md) 14 | - [Accessibility](/docs/ui/accessibility.md) 15 | - [Roadmap](/docs/roadmap.pdf) 16 | 17 | # Something missing? 18 | 19 | To request additional documentation or report an issue with existing resources, visit [the Issues tab](https://github.com/google/testrun/issues/new/choose). 20 | -------------------------------------------------------------------------------- /docs/dev/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/dev/architecture.png -------------------------------------------------------------------------------- /docs/roadmap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/roadmap.pdf -------------------------------------------------------------------------------- /docs/setup/install.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/setup/install.gif -------------------------------------------------------------------------------- /docs/setup/visual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/setup/visual.png -------------------------------------------------------------------------------- /docs/test/README.md: -------------------------------------------------------------------------------- 1 | Testrun logo 2 | 3 | # Testing 4 | 5 | Testrun provides modules for you to test your own device. You can learn more about the requirements for each on the [Test modules page](/docs/test/modules.md). The [Test results page](/docs/test/statuses.md) outlines possible results and how to interpret them. 6 | -------------------------------------------------------------------------------- /docs/ui/accessibility.md: -------------------------------------------------------------------------------- 1 | Testrun logo 2 | 3 | # Accessibility 4 | 5 | We designed Testrun with accessibility at its core. The application provides full support for: 6 | 7 | - Screen readers 8 | - Keyboard navigation 9 | - Responsive resizing and scaling 10 | - [Helperbird](https://www.helperbird.com/) 11 | 12 | For a more thorough explanation of these features, download the [accessibility video](https://github.com/google/testrun/raw/main/docs/ui/accessibility.mp4). If you require further accommodations when using Testrun, please [raise an issue](https://github.com/google/testrun/issues/new/choose). -------------------------------------------------------------------------------- /docs/ui/accessibility.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/accessibility.mp4 -------------------------------------------------------------------------------- /docs/ui/getstarted--2dn8vrzsspe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted--2dn8vrzsspe.png -------------------------------------------------------------------------------- /docs/ui/getstarted--3d9k3si3ul1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted--3d9k3si3ul1.png -------------------------------------------------------------------------------- /docs/ui/getstarted-actions-device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-actions-device.png -------------------------------------------------------------------------------- /docs/ui/getstarted-actions-testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-actions-testing.png -------------------------------------------------------------------------------- /docs/ui/getstarted-add-device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-add-device.png -------------------------------------------------------------------------------- /docs/ui/getstarted-certificates-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-certificates-menu.png -------------------------------------------------------------------------------- /docs/ui/getstarted-device-repository.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-device-repository.png -------------------------------------------------------------------------------- /docs/ui/getstarted-reports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-reports.png -------------------------------------------------------------------------------- /docs/ui/getstarted-risk-assessment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-risk-assessment.png -------------------------------------------------------------------------------- /docs/ui/getstarted-settings-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-settings-menu.png -------------------------------------------------------------------------------- /docs/ui/getstarted-testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-testing.png -------------------------------------------------------------------------------- /docs/ui/getstarted-waiting-for-device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/docs/ui/getstarted-waiting-for-device.png -------------------------------------------------------------------------------- /framework/python/src/net_orc/network_event.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Specify the various types of network events to be reported.""" 16 | from enum import Enum 17 | 18 | 19 | class NetworkEvent(Enum): 20 | """All possible network events.""" 21 | DEVICE_DISCOVERED = 1 22 | DEVICE_STABLE = 2 23 | DHCP_LEASE_ACK = 3 24 | -------------------------------------------------------------------------------- /framework/requirements.txt: -------------------------------------------------------------------------------- 1 | # Requirements for the core module 2 | requests==2.32.3 3 | 4 | # Requirements for the net_orc module 5 | docker==7.1.0 6 | ipaddress==1.0.23 7 | netifaces==0.11.0 8 | scapy==2.5.0 9 | 10 | # Requirments for the test_orc module 11 | weasyprint==61.2 12 | pydyf==0.8.0 13 | 14 | # Requirements for the API 15 | fastapi==0.109.1 16 | psutil==5.9.8 17 | uvicorn==0.27.0 18 | python-multipart==0.0.19 19 | pydantic==2.7.1 20 | 21 | # Requirements for testing 22 | pytest==7.4.4 23 | pytest-timeout==2.2.0 24 | responses==0.25.3 25 | 26 | 27 | # Requirements for the report 28 | markdown==3.5.2 29 | 30 | # Requirements for the session 31 | cryptography==44.0.1 32 | pytz==2024.1 33 | 34 | # Requirements for the risk profile 35 | python-dateutil==2.9.0 36 | 37 | # Requirements for MQTT client 38 | paho-mqtt==2.1.0 39 | 40 | # Requirements for background tasks 41 | APScheduler==3.10.4 42 | 43 | # Requirements for reports generation 44 | Jinja2==3.1.6 45 | beautifulsoup4==4.12.3 46 | -------------------------------------------------------------------------------- /local/.gitignore: -------------------------------------------------------------------------------- 1 | system.json 2 | devices 3 | root_certs 4 | risk_profiles 5 | -------------------------------------------------------------------------------- /local/system.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "device_intf": "", 4 | "internet_intf": "" 5 | }, 6 | "log_level": "INFO", 7 | "startup_timeout": 60, 8 | "monitor_period": 300, 9 | "allow_disconnect": false, 10 | "max_device_reports": 0, 11 | "org_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /make/.gitignore: -------------------------------------------------------------------------------- 1 | usr/ 2 | bin/ 3 | DEBIAN/postinst -------------------------------------------------------------------------------- /make/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: Testrun 2 | Version: 2.2.1 3 | Architecture: amd64 4 | Maintainer: Google 5 | Homepage: https://github.com/google/testrun 6 | Bugs: https://github.com/google/testrun/issues 7 | Description: Automatically verify IoT device network behavior 8 | Depends: libpangocairo-1.0-0, openvswitch-common, openvswitch-switch, build-essential, python3, python3-dev, python3-venv, net-tools, ethtool 9 | -------------------------------------------------------------------------------- /make/DEBIAN/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | echo Finished uninstalling Testrun -------------------------------------------------------------------------------- /make/DEBIAN/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Stop any running containers 18 | echo Stopping any running containers 19 | running_containers=$(docker container ls -q --filter name=tr-*) 20 | if [ -n "$running_containers" ]; then 21 | docker container kill $running_containers 22 | else 23 | echo No containers were found running 24 | fi 25 | 26 | # Remove docker images 27 | echo Removing docker images 28 | docker_images=$(sudo docker images --filter=reference="test-run/*" -q) 29 | 30 | if [ -z "$docker_images" ]; then 31 | echo No docker images to delete 32 | else 33 | sudo docker rmi -f $docker_images > /dev/null 34 | fi -------------------------------------------------------------------------------- /modules/devices/faux-dev/bin/get_default_gateway: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | route | grep default | awk '{print $2}' -------------------------------------------------------------------------------- /modules/devices/faux-dev/bin/start_dhcp_client: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Fetch the interface 18 | INTF=$1 19 | 20 | PID_FILE=/var/run/dhclient.pid 21 | 22 | echo "Starting DHCP Client on interface $INTF" 23 | 24 | #Kill any existing running dhclient process 25 | if [ -f $PID_FILE ]; then 26 | kill -9 $(cat $PID_FILE) || true 27 | rm -f $PID_FILE 28 | fi 29 | 30 | dhclient $INTF -------------------------------------------------------------------------------- /modules/devices/faux-dev/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "faux-dev", 5 | "description": "Faux device to test network modules are functioning properly" 6 | }, 7 | "docker": { 8 | "timeout": 60 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /modules/network/base/bin/setup_binaries: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Directory where all binaries will be loaded 18 | BIN_DIR=$1 19 | 20 | # Remove incorrect line endings 21 | dos2unix $BIN_DIR/* 22 | 23 | # Make sure all the bin files are executable 24 | chmod u+x $BIN_DIR/* -------------------------------------------------------------------------------- /modules/network/base/bin/setup_python_path: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ROOT_DIRECTORY="/testrun/python/src" 4 | 5 | # Function to recursively add subdirectories to PYTHONPATH 6 | add_subdirectories_to_pythonpath() { 7 | local directory=$1 8 | local subdirectories=( "$directory"/* ) 9 | local subdirectory 10 | 11 | for subdirectory in "${subdirectories[@]}"; do 12 | if [[ -d "$subdirectory" && ! "$subdirectory" = *'__pycache__' ]]; then 13 | export PYTHONPATH="$PYTHONPATH:$subdirectory" 14 | add_subdirectories_to_pythonpath "$subdirectory" 15 | fi 16 | done 17 | } 18 | 19 | # Set PYTHONPATH initially to an empty string 20 | export PYTHONPATH="$ROOT_DIRECTORY" 21 | 22 | # Add all subdirectories to PYTHONPATH 23 | add_subdirectories_to_pythonpath "$ROOT_DIRECTORY" 24 | 25 | echo "$PYTHONPATH" -------------------------------------------------------------------------------- /modules/network/base/bin/start_grpc: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | GRPC_DIR="/testrun/python/src/grpc_server" 18 | GRPC_PROTO_DIR="proto" 19 | GRPC_PROTO_FILE="grpc.proto" 20 | 21 | #Move into the grpc directory 22 | pushd $GRPC_DIR >/dev/null 2>&1 23 | 24 | #Build the grpc proto file every time before starting server 25 | python3 -u -m grpc_tools.protoc --proto_path=. ./$GRPC_PROTO_DIR/$GRPC_PROTO_FILE --python_out=. --grpc_python_out=. 26 | 27 | popd >/dev/null 2>&1 28 | 29 | #Start the grpc server 30 | python3 -u $GRPC_DIR/start_server.py $@ & 31 | 32 | -------------------------------------------------------------------------------- /modules/network/base/bin/start_network_service: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Place holder function for testing and validation 18 | # Each network module should include a start_networkig_service 19 | # file that overwrites this one to boot all of the its specific 20 | # requirements to run. 21 | 22 | echo "Starting network service..." 23 | echo "This is not a real network service, just a test" 24 | echo "Network service started" -------------------------------------------------------------------------------- /modules/network/base/bin/wait_for_interface: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Default interface should be veth0 for all containers 18 | DEFAULT_IFACE=veth0 19 | 20 | # Allow a user to define an interface by passing it into this script 21 | DEFINED_IFACE=$1 22 | 23 | # Select which interace to use 24 | if [[ -z $DEFINED_IFACE ]] 25 | then 26 | INTF=$DEFAULT_IFACE 27 | else 28 | INTF=$DEFINED_IFACE 29 | fi 30 | 31 | # Wait for local interface to be ready 32 | while ! ip link show $INTF; do 33 | echo $INTF is not yet ready. Waiting 3 seconds 34 | sleep 3 35 | done -------------------------------------------------------------------------------- /modules/network/base/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "base", 5 | "display_name": "Base", 6 | "description": "Base image" 7 | }, 8 | "docker": { 9 | "enable_container": false 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /modules/network/base/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | protobuf==5.28.3 5 | 6 | # User defined packages 7 | grpcio==1.67.1 8 | grpcio-tools==1.67.1 9 | netifaces==0.11.0 10 | 11 | -------------------------------------------------------------------------------- /modules/network/dhcp-1/conf/dhcpd.conf: -------------------------------------------------------------------------------- 1 | default-lease-time 30; 2 | max-lease-time 30; 3 | 4 | failover peer "failover-peer" { 5 | primary; 6 | address 10.10.10.2; 7 | port 847; 8 | peer address 10.10.10.3; 9 | peer port 647; 10 | max-response-delay 60; 11 | max-unacked-updates 10; 12 | mclt 30; 13 | split 128; 14 | load balance max seconds 3600; 15 | } 16 | 17 | subnet 10.10.10.0 netmask 255.255.255.0 { 18 | option ntp-servers 10.10.10.5; 19 | option subnet-mask 255.255.255.0; 20 | option broadcast-address 10.10.10.255; 21 | option routers 10.10.10.1; 22 | option domain-name-servers 10.10.10.4; 23 | interface veth0; 24 | authoritative; 25 | pool { 26 | failover peer "failover-peer"; 27 | range 10.10.10.10 10.10.10.20; 28 | } 29 | } -------------------------------------------------------------------------------- /modules/network/dhcp-1/conf/isc-dhcp-server: -------------------------------------------------------------------------------- 1 | # On what interfaces should the DHCP server (dhcpd) serve DHCP requests? 2 | # Separate multiple interfaces with spaces, e.g. "eth0 eth1". 3 | INTERFACESv4="veth0" 4 | #INTERFACESv6="veth0" 5 | -------------------------------------------------------------------------------- /modules/network/dhcp-1/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "dhcp-1", 5 | "display_name": "DHCP Primary", 6 | "description": "Primary DHCP server with IPv6 SLAAC" 7 | }, 8 | "network": { 9 | "interface": "veth0", 10 | "enable_wan": false, 11 | "ip_index": 2 12 | }, 13 | "grpc":{ 14 | "port": 5001 15 | }, 16 | "docker": { 17 | "depends_on": "base", 18 | "mounts": [ 19 | { 20 | "source": "runtime/network", 21 | "target": "/runtime/network" 22 | } 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /modules/network/dhcp-1/conf/radvd.conf: -------------------------------------------------------------------------------- 1 | interface veth0 2 | { 3 | AdvSendAdvert on; 4 | AdvManagedFlag off; 5 | MinRtrAdvInterval 10; 6 | MaxRtrAdvInterval 30; 7 | prefix fd10:77be:4186::/64 { 8 | AdvOnLink on; 9 | AdvAutonomous on; 10 | AdvRouterAddr on; 11 | AdvValidLifetime 60; 12 | AdvPreferredLifetime 30; 13 | }; 14 | }; -------------------------------------------------------------------------------- /modules/network/dhcp-1/dhcp-1.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/dhcp-primary 16 | FROM testrun/base:latest 17 | 18 | ARG MODULE_NAME=dhcp-1 19 | ARG MODULE_DIR=modules/network/$MODULE_NAME 20 | 21 | #Update and get all additional requirements not contained in the base image 22 | RUN apt-get update --fix-missing 23 | 24 | # Install all necessary packages 25 | RUN apt-get install -y wget 26 | 27 | # Install dhcp server 28 | RUN apt-get install -y isc-dhcp-server radvd systemd 29 | 30 | # Copy over all configuration files 31 | COPY $MODULE_DIR/conf /testrun/conf 32 | 33 | # Copy over all binary files 34 | COPY $MODULE_DIR/bin /testrun/bin 35 | 36 | # Copy over all python files 37 | COPY $MODULE_DIR/python /testrun/python 38 | -------------------------------------------------------------------------------- /modules/network/dhcp-1/python/src/grpc_server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/modules/network/dhcp-1/python/src/grpc_server/__init__.py -------------------------------------------------------------------------------- /modules/network/dhcp-2/conf/dhcpd.conf: -------------------------------------------------------------------------------- 1 | default-lease-time 30; 2 | max-lease-time 30; 3 | 4 | failover peer "failover-peer" { 5 | secondary; 6 | address 10.10.10.3; 7 | port 647; 8 | peer address 10.10.10.2; 9 | peer port 847; 10 | max-response-delay 60; 11 | max-unacked-updates 10; 12 | } 13 | 14 | subnet 10.10.10.0 netmask 255.255.255.0 { 15 | option ntp-servers 10.10.10.5; 16 | option subnet-mask 255.255.255.0; 17 | option broadcast-address 10.10.10.255; 18 | option routers 10.10.10.1; 19 | option domain-name-servers 10.10.10.4; 20 | interface veth0; 21 | pool { 22 | failover peer "failover-peer"; 23 | range 10.10.10.10 10.10.10.20; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /modules/network/dhcp-2/conf/isc-dhcp-server: -------------------------------------------------------------------------------- 1 | # On what interfaces should the DHCP server (dhcpd) serve DHCP requests? 2 | # Separate multiple interfaces with spaces, e.g. "eth0 eth1". 3 | INTERFACESv4="veth0" 4 | #INTERFACESv6="veth0" 5 | -------------------------------------------------------------------------------- /modules/network/dhcp-2/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "dhcp-2", 5 | "display_name": "DHCP Secondary", 6 | "description": "Secondary DHCP server with IPv6 SLAAC" 7 | }, 8 | "network": { 9 | "interface": "veth0", 10 | "enable_wan": false, 11 | "ip_index": 3 12 | }, 13 | "grpc":{ 14 | "port": 5001 15 | }, 16 | "docker": { 17 | "depends_on": "base", 18 | "mounts": [ 19 | { 20 | "source": "runtime/network", 21 | "target": "/runtime/network" 22 | } 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /modules/network/dhcp-2/conf/radvd.conf: -------------------------------------------------------------------------------- 1 | interface veth0 2 | { 3 | AdvSendAdvert on; 4 | AdvManagedFlag off; 5 | MinRtrAdvInterval 10; 6 | MaxRtrAdvInterval 30; 7 | prefix fd10:77be:4186::/64 { 8 | AdvOnLink on; 9 | AdvAutonomous on; 10 | AdvRouterAddr on; 11 | AdvValidLifetime 60; 12 | AdvPreferredLifetime 30; 13 | }; 14 | }; -------------------------------------------------------------------------------- /modules/network/dhcp-2/dhcp-2.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/dhcp-primary 16 | FROM testrun/base:latest 17 | 18 | ARG MODULE_NAME=dhcp-2 19 | ARG MODULE_DIR=modules/network/$MODULE_NAME 20 | 21 | # Update and get all additional requirements not contained in the base image 22 | RUN apt-get update --fix-missing 23 | 24 | # Install all necessary packages 25 | RUN apt-get install -y wget 26 | 27 | # Install dhcp server 28 | RUN apt-get install -y isc-dhcp-server radvd systemd 29 | 30 | # Copy over all configuration files 31 | COPY $MODULE_DIR/conf /testrun/conf 32 | 33 | # Copy over all binary files 34 | COPY $MODULE_DIR/bin /testrun/bin 35 | 36 | # Copy over all python files 37 | COPY $MODULE_DIR/python /testrun/python 38 | -------------------------------------------------------------------------------- /modules/network/dhcp-2/python/src/grpc_server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/modules/network/dhcp-2/python/src/grpc_server/__init__.py -------------------------------------------------------------------------------- /modules/network/dns/conf/dnsmasq.conf: -------------------------------------------------------------------------------- 1 | server=8.8.8.8 2 | 3 | interface=veth0 4 | 5 | log-queries -------------------------------------------------------------------------------- /modules/network/dns/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "dns", 5 | "display_name": "DNS", 6 | "description": "A DNS server" 7 | }, 8 | "network": { 9 | "interface": "veth0", 10 | "enable_wan": false, 11 | "ip_index": 4 12 | }, 13 | "docker": { 14 | "depends_on": "base", 15 | "mounts": [ 16 | { 17 | "source": "runtime/network", 18 | "target": "/runtime/network" 19 | } 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /modules/network/dns/dns.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/dns 16 | FROM testrun/base:latest 17 | 18 | ARG MODULE_NAME=dns 19 | ARG MODULE_DIR=modules/network/$MODULE_NAME 20 | 21 | #Update and get all additional requirements not contained in the base image 22 | RUN apt-get update --fix-missing 23 | 24 | #Install dnsmasq 25 | RUN apt-get install -y dnsmasq 26 | 27 | # Copy over all configuration files 28 | COPY $MODULE_DIR/conf /testrun/conf 29 | 30 | # Copy over all binary files 31 | COPY $MODULE_DIR/bin /testrun/bin 32 | -------------------------------------------------------------------------------- /modules/network/gateway/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "gateway", 5 | "display_name": "Gateway", 6 | "description": "Enable internet connectivity on device bridge" 7 | }, 8 | "network": { 9 | "interface": "veth0", 10 | "enable_wan": true, 11 | "ip_index": 1 12 | }, 13 | "docker": { 14 | "depends_on": "base", 15 | "mounts": [ 16 | { 17 | "source": "runtime/network", 18 | "target": "/runtime/network" 19 | } 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /modules/network/gateway/gateway.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/gateway 16 | FROM testrun/base:latest 17 | 18 | ARG MODULE_NAME=gateway 19 | ARG MODULE_DIR=modules/network/$MODULE_NAME 20 | 21 | # Install required packages 22 | RUN apt-get update && apt-get install -y iptables isc-dhcp-client 23 | 24 | # Copy over all configuration files 25 | COPY $MODULE_DIR/conf /testrun/conf 26 | 27 | # Copy over all binary files 28 | COPY $MODULE_DIR/bin /testrun/bin 29 | -------------------------------------------------------------------------------- /modules/network/host/bin/start_network_service: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | echo "Starting host service..." 18 | 19 | # Keep host container running until stopped 20 | while true; do 21 | sleep 3 22 | done 23 | -------------------------------------------------------------------------------- /modules/network/host/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "host", 5 | "display_name": "Host", 6 | "description": "Used to access host level networking operations" 7 | }, 8 | "network": { 9 | "host": true 10 | }, 11 | "grpc":{ 12 | "port": 5001 13 | }, 14 | "docker": { 15 | "depends_on": "base", 16 | "mounts": [ 17 | { 18 | "source": "runtime/network", 19 | "target": "/runtime/network" 20 | } 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /modules/network/host/host.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/host 16 | FROM testrun/base:latest 17 | 18 | ARG MODULE_NAME=host 19 | ARG MODULE_DIR=modules/network/$MODULE_NAME 20 | 21 | #Update and get all additional requirements not contained in the base image 22 | RUN apt-get update --fix-missing 23 | 24 | # Install all necessary packages 25 | RUN apt-get install -y net-tools ethtool 26 | 27 | # Copy over all configuration files 28 | COPY $MODULE_DIR/conf /testrun/conf 29 | 30 | # Copy over all binary files 31 | COPY $MODULE_DIR/bin /testrun/bin 32 | 33 | # Copy over all python files 34 | COPY $MODULE_DIR/python /testrun/python 35 | -------------------------------------------------------------------------------- /modules/network/host/python/src/grpc_server/proto/grpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | service HostNetworkModule { 4 | 5 | rpc CheckInterfaceStatus(CheckInterfaceStatusRequest) returns (CheckInterfaceStatusResponse) {}; 6 | rpc GetIfaceConnectionStats(GetIfaceStatsRequest) returns (GetIfaceStatsResponse) {}; 7 | rpc SetIfaceDown(SetIfaceRequest) returns (SetIfaceResponse) {}; 8 | rpc SetIfaceUp(SetIfaceRequest) returns (SetIfaceResponse) {}; 9 | } 10 | 11 | message CheckInterfaceStatusRequest { 12 | string iface_name = 1; 13 | } 14 | 15 | message CheckInterfaceStatusResponse { 16 | int32 code = 1; 17 | bool status = 2; 18 | } 19 | 20 | message GetIfaceStatsRequest { 21 | string iface_name = 1; 22 | } 23 | 24 | message GetIfaceStatsResponse { 25 | int32 code = 1; 26 | string stats = 2; 27 | } 28 | 29 | message SetIfaceRequest { 30 | string iface_name = 1; 31 | } 32 | 33 | message SetIfaceResponse { 34 | int32 code = 1; 35 | bool success = 2; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /modules/network/ntp/bin/start_network_service: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | PYTHON_SRC_DIR=/testrun/python/src 18 | LOG_FILE="/runtime/network/ntp.log" 19 | 20 | echo Starting ntp 21 | 22 | # Route internet traffic through gateway 23 | ip route add default via 10.10.10.1 dev veth0 24 | 25 | #Create and set permissions on the log file 26 | touch $LOG_FILE 27 | chown $HOST_USER $LOG_FILE 28 | 29 | # Move the config files to the correct location 30 | cp /testrun/conf/chrony.conf /etc/chrony/ 31 | 32 | #Start the NTP server 33 | python3 -u $PYTHON_SRC_DIR/ntp_server.py > $LOG_FILE 34 | -------------------------------------------------------------------------------- /modules/network/ntp/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "ntp", 5 | "display_name": "NTP", 6 | "description": "An NTP server" 7 | }, 8 | "network": { 9 | "interface": "veth0", 10 | "enable_wan": false, 11 | "ip_index": 5 12 | }, 13 | "docker": { 14 | "depends_on": "base", 15 | "mounts": [ 16 | { 17 | "source": "runtime/network", 18 | "target": "/runtime/network" 19 | } 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /modules/network/ntp/ntp.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/ntp 16 | FROM testrun/base:latest 17 | 18 | ARG MODULE_NAME=ntp 19 | ARG MODULE_DIR=modules/network/$MODULE_NAME 20 | 21 | # Set DEBIAN_FRONTEND to noninteractive mode 22 | ENV DEBIAN_FRONTEND=noninteractive 23 | 24 | RUN apt-get update 25 | 26 | # Install all necessary packages 27 | RUN apt-get install -y chrony 28 | 29 | # Copy over all configuration files 30 | COPY $MODULE_DIR/conf /testrun/conf 31 | 32 | # Copy over all binary files 33 | COPY $MODULE_DIR/bin /testrun/bin 34 | 35 | # Copy over all python files 36 | COPY $MODULE_DIR/python /testrun/python 37 | 38 | EXPOSE 123/udp 39 | -------------------------------------------------------------------------------- /modules/network/radius/bin/start_network_service: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | PYTHON_SRC_DIR=/testrun/python/src 18 | CONF_DIR="/testrun/conf" 19 | LOG_FILE="/runtime/network/radius.log" 20 | 21 | echo Starting authenticator.py 22 | 23 | cp $CONF_DIR/eap /etc/freeradius/3.0/mods-available/eap 24 | 25 | # Do we want to mount resources/network/{module} to the network module to avoid file copying during build? 26 | cp $CONF_DIR/ca.crt /etc/ssl/certs/ca-certificates.crt 27 | 28 | python3 -u $PYTHON_SRC_DIR/authenticator.py & 29 | 30 | # Create and set permissions on the log file 31 | touch $LOG_FILE 32 | chown $HOST_USER $LOG_FILE 33 | 34 | freeradius -f -X &> $LOG_FILE -------------------------------------------------------------------------------- /modules/network/radius/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "enabled": false, 4 | "meta": { 5 | "name": "radius", 6 | "display_name": "Radius", 7 | "description": "Enable port based authentication" 8 | }, 9 | "network": { 10 | "interface": "veth0", 11 | "enable_wan": false, 12 | "ip_index": 7 13 | }, 14 | "docker": { 15 | "depends_on": "base", 16 | "mounts": [ 17 | { 18 | "source": "runtime/network", 19 | "target": "/runtime/network" 20 | } 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /modules/network/radius/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | dnspython==2.6.1 5 | greenlet==3.0.3 6 | six==1.16.0 7 | 8 | # User defined packages 9 | eventlet==0.36.1 10 | pbr==6.1.0 11 | transitions==0.9.2 12 | -------------------------------------------------------------------------------- /modules/network/template/bin/start_network_service: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Place holder function for testing and validation 18 | # Each network module should include a start_networkig_service 19 | # file that overwrites this one to boot all of the its specific 20 | # requirements to run. 21 | 22 | echo "Starting network service..." 23 | echo "This is not a real network service, just a test" 24 | echo "Network service started" 25 | 26 | # Do Nothing, just keep the module alive 27 | while true; do sleep 1; done -------------------------------------------------------------------------------- /modules/network/template/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "template", 5 | "display_name": "Template", 6 | "description": "Template for building network service modules" 7 | }, 8 | "network": { 9 | "interface": "veth0", 10 | "enable_wan": false, 11 | "ip_index": 9 12 | }, 13 | "grpc": { 14 | "port": 50001 15 | }, 16 | "docker": { 17 | "enable_container": false, 18 | "template":true, 19 | "depends_on": "base", 20 | "mounts": [ 21 | { 22 | "source": "runtime/network", 23 | "target": "/runtime/network" 24 | } 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /modules/network/template/python/src/template_main.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Python code for the template module.""" 16 | 17 | if __name__ == "__main__": 18 | print("Template main") 19 | -------------------------------------------------------------------------------- /modules/network/template/template.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/template 16 | FROM testrun/base:latest 17 | 18 | ARG MODULE_NAME=template 19 | ARG MODULE_DIR=modules/network/$MODULE_NAME 20 | 21 | # Copy over all configuration files 22 | COPY $MODULE_DIR/conf /testrun/conf 23 | 24 | # Copy over all binary files 25 | COPY $MODULE_DIR/bin /testrun/bin 26 | 27 | # Copy over all python files 28 | COPY $MODULE_DIR/python /testrun/python -------------------------------------------------------------------------------- /modules/test/base/bin/capture: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Fetch module name 18 | MODULE_NAME=$1 19 | 20 | # Define the local file location for the capture to be saved 21 | PCAP_DIR="/runtime/output" 22 | PCAP_FILE=$MODULE_NAME.pcap 23 | 24 | # Allow a user to define an interface by passing it into this script 25 | INTERFACE=$2 26 | 27 | # Create the output directory and start the capture 28 | mkdir -p $PCAP_DIR 29 | chown $HOST_USER $PCAP_DIR 30 | tcpdump -U -i $INTERFACE -w $PCAP_DIR/$PCAP_FILE -Z $HOST_USER & 31 | 32 | # Small pause to let the capture to start 33 | sleep 1 -------------------------------------------------------------------------------- /modules/test/base/bin/get_ipv4_addr: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | NET=$1 18 | MAC=$2 19 | 20 | IP_ADDR=$(nmap -sP $NET | grep -B 2 $MAC | head -n 1 | cut -d " " -f 5) 21 | 22 | echo $IP_ADDR -------------------------------------------------------------------------------- /modules/test/base/bin/setup_binaries: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Directory where all binaries will be loaded 18 | BIN_DIR=$1 19 | 20 | # Remove incorrect line endings 21 | dos2unix $BIN_DIR/* 22 | 23 | # Make sure all the bin files are executable 24 | chmod u+x $BIN_DIR/* -------------------------------------------------------------------------------- /modules/test/base/bin/setup_grpc_clients: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | GRPC_DIR="/testrun/python/src/grpc_server" 4 | GRPC_PROTO_DIR="proto" 5 | GRPC_PROTO_FILE="grpc.proto" 6 | 7 | # Build the grpc proto file 8 | build_grpc_client(){ 9 | MODULE=$1 10 | echo "Building gRPC proto: $MODULE" 11 | python3 -m grpc_tools.protoc --proto_path=. ./$GRPC_PROTO_DIR/$MODULE/$GRPC_PROTO_FILE --python_out=. --grpc_python_out=. 12 | } 13 | 14 | # Build the grpc proto files for every module that has a proto defined 15 | build_grpc_clients(){ 16 | 17 | for dir in "$GRPC_DIR/$GRPC_PROTO_DIR"/*/;do 18 | if [ -f $dir/$GRPC_PROTO_FILE ];then 19 | # Extract the last folder name 20 | last_folder="${dir%%/}" 21 | last_folder="${last_folder##*/}" 22 | build_grpc_client "$last_folder" 23 | fi 24 | done 25 | } 26 | 27 | # Move into the grpc directory. 28 | # This is necessary to build the proto files 29 | # with the correct import paths 30 | pushd $GRPC_DIR >/dev/null 2>&1 31 | 32 | build_grpc_clients 33 | 34 | popd >/dev/null 2>&1 -------------------------------------------------------------------------------- /modules/test/base/bin/setup_python_path: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ROOT_DIRECTORY="/testrun/python/src" 4 | 5 | # Function to recursively add subdirectories to PYTHONPATH 6 | add_subdirectories_to_pythonpath() { 7 | local directory=$1 8 | local subdirectories=( "$directory"/* ) 9 | local subdirectory 10 | 11 | for subdirectory in "${subdirectories[@]}"; do 12 | if [ -d "$subdirectory" ]; then 13 | export PYTHONPATH="$PYTHONPATH:$subdirectory" 14 | add_subdirectories_to_pythonpath "$subdirectory" 15 | fi 16 | done 17 | } 18 | 19 | # Set PYTHONPATH initially to an empty string 20 | export PYTHONPATH="" 21 | 22 | # Add all subdirectories to PYTHONPATH 23 | add_subdirectories_to_pythonpath "$ROOT_DIRECTORY" 24 | 25 | echo "$PYTHONPATH" -------------------------------------------------------------------------------- /modules/test/base/bin/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Allow one argument which is the unit test file to run 18 | # instead of running the test module 19 | UNIT_TEST_FILE=$1 20 | 21 | source /testrun/bin/setup 22 | 23 | # Conditionally run start_module based on RUN 24 | if [[ -z "$UNIT_TEST_FILE" ]];then 25 | /testrun/bin/start_module 26 | else 27 | python3 $UNIT_TEST_FILE 28 | fi 29 | -------------------------------------------------------------------------------- /modules/test/base/bin/start_grpc: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | GRPC_DIR="/testrun/python/src/grpc" 18 | GRPC_PROTO_DIR="proto" 19 | GRPC_PROTO_FILE="grpc.proto" 20 | 21 | # Move into the grpc directory 22 | pushd $GRPC_DIR >/dev/null 2>&1 23 | 24 | # Build the grpc proto file every time before starting server 25 | python3 -m grpc_tools.protoc --proto_path=. ./$GRPC_PROTO_DIR/$GRPC_PROTO_FILE --python_out=. --grpc_python_out=. 26 | 27 | popd >/dev/null 2>&1 28 | 29 | # Start the grpc server 30 | python3 -u $GRPC_DIR/start_server.py $@ 31 | 32 | -------------------------------------------------------------------------------- /modules/test/base/bin/wait_for_interface: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Allow a user to define an interface by passing it into this script 18 | INTF=$1 19 | 20 | # Wait for local interface to be ready 21 | while ! ip link show $INTF; do 22 | echo $INTF is not yet ready. Waiting 3 seconds 23 | sleep 3 24 | done -------------------------------------------------------------------------------- /modules/test/base/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "base", 5 | "display_name": "Base", 6 | "description": "Base image" 7 | }, 8 | "network": false, 9 | "docker": { 10 | "enable_container": false 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /modules/test/base/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | protobuf==5.28.0 5 | 6 | # User defined packages 7 | grpcio==1.67.1 8 | grpcio-tools==1.67.1 9 | netifaces==0.11.0 10 | 11 | # Requirements for reports generation 12 | Jinja2==3.1.6 13 | -------------------------------------------------------------------------------- /modules/test/baseline/README.md: -------------------------------------------------------------------------------- 1 | # Baseline Test Module 2 | 3 | The baseline test module runs a test for each result status type. This is used for testing purposes - to ensure that the test framework is operational. 4 | 5 | This module is disabled by default when testing a physical device and there is no need for this to be enabled. 6 | 7 | ## What's inside? 8 | 9 | The ```bin``` folder contains the startup script for the module. 10 | 11 | The ```config/module_config.json``` provides the name and description of the module, and specifies which tests will be caried out. 12 | 13 | Within the ```python/src``` directory, the below tests are executed. 14 | 15 | ## Tests covered 16 | 17 | | ID | Description | Expected behavior | Required result 18 | |---|---|---|---| 19 | | baseline.compliant | Simulate a compliant test | A compliant test result is generated | Required | 20 | | baseline.skipped | Simulate an skipped test | An skipped test result is generated | Skipped | 21 | | baseline.non-compliant | Simulate a non-compliant test | A non-compliant test result is generated | Required | -------------------------------------------------------------------------------- /modules/test/baseline/baseline.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/baseline-test 16 | FROM testrun/base-test:latest 17 | 18 | ARG MODULE_NAME=baseline 19 | ARG MODULE_DIR=modules/test/$MODULE_NAME 20 | 21 | # Copy over all configuration files 22 | COPY $MODULE_DIR/conf /testrun/conf 23 | 24 | # Copy over all binary files 25 | COPY $MODULE_DIR/bin /testrun/bin 26 | 27 | # Copy over all python files 28 | COPY $MODULE_DIR/python /testrun/python -------------------------------------------------------------------------------- /modules/test/baseline/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "enabled": false, 4 | "meta": { 5 | "name": "baseline", 6 | "display_name": "Baseline", 7 | "description": "Baseline test" 8 | }, 9 | "network": false, 10 | "docker": { 11 | "depends_on": "base", 12 | "enable_container": true, 13 | "timeout": 30 14 | }, 15 | "tests":[ 16 | { 17 | "name": "baseline.compliant", 18 | "test_description": "Simulate a compliant test", 19 | "expected_behavior": "A compliant test result is generated" 20 | }, 21 | { 22 | "name": "baseline.non_compliant", 23 | "test_description": "Simulate a non-compliant test", 24 | "expected_behavior": "A non-compliant test result is generated" 25 | }, 26 | { 27 | "name": "baseline.skipped", 28 | "test_description": "Simulate a skipped test", 29 | "expected_behavior": "A skipped test result is generated" 30 | } 31 | ] 32 | } 33 | } -------------------------------------------------------------------------------- /modules/test/conn/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | cffi==1.17.1 5 | cryptography==44.0.1 6 | pycparser==2.22 7 | six==1.16.0 8 | 9 | # User defined packages 10 | pyOpenSSL==24.3.0 11 | scapy==2.6.0 12 | python-dateutil==2.9.0.post0 13 | -------------------------------------------------------------------------------- /modules/test/dns/README.md: -------------------------------------------------------------------------------- 1 | # DNS Test Module 2 | 3 | The DNS test module inspects the device's behavior when attempting to resolve hostnames. 4 | 5 | ## What's inside? 6 | 7 | The ```bin``` folder contains the startup script for the module. 8 | 9 | The ```config/module_config.json``` provides the name and description of the module, and specifies which tests will be caried out. 10 | 11 | Within the ```python/src``` directory, the below tests are executed. 12 | 13 | ## Tests covered 14 | 15 | | ID | Description | Expected behavior | Required result 16 | |---|---|---|---| 17 | | dns.network.hostname_resolution | Verifies that the device resolves hostnames | The device sends DNS requests | Required | 18 | | dns.network.from_dhcp | Verifies that the device allows for a DNS server to be provided by the DHCP server | The device sends DNS requests to the DNS server provided by the DHCP server | Informational | 19 | | dns.mdns | Does the device has MDNS | Device may send MDNS requests | Informational | 20 | -------------------------------------------------------------------------------- /modules/test/dns/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | 5 | # User defined packages 6 | scapy==2.6.0 7 | -------------------------------------------------------------------------------- /modules/test/dns/resources/report_template.jinja2: -------------------------------------------------------------------------------- 1 | {% extends base_template %} 2 | {% block content %} 3 | {% if module_data %} 4 | 5 | 6 | 7 | {% for header in module_data_headers %} 8 | 9 | {% endfor %} 10 | 11 | 12 | 13 | {% for row in module_data %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% endfor %} 23 | 24 |
{{ header }}
{{ row['src'] }}
{{ row['dst'] }}
{{ row['res_ip'] }}
{{ row['typ'] }}
{{ row['dat'] }}
{{ row['count'] }}
25 | {% else %} 26 |
27 |
28 | No DNS traffic detected from the device 29 |
30 | {% endif %} 31 | {% endblock %} -------------------------------------------------------------------------------- /modules/test/ntp/README.md: -------------------------------------------------------------------------------- 1 | # NTP Test Module 2 | 3 | The NTP test module verifies the device behavior when syncing time with an NTP server. 4 | 5 | ## What's inside? 6 | 7 | The ```bin``` folder contains the startup script for the module. 8 | 9 | The ```config/module_config.json``` provides the name and description of the module, and specifies which tests will be caried out. 10 | 11 | Within the ```python/src``` directory, the below tests are executed. 12 | 13 | ## Tests covered 14 | 15 | | ID | Description | Expected behavior | Required result 16 | |---|---|---|---| 17 | | ntp.network.ntp_support | Does the device request network time using NTPv4 | The device sends an NTPv4 request to the configured NTP server | Required | 18 | | ntp.network.ntp_dhcp | Checks the device can accept an NTP server address from the DHCP server | Device can accept NTP server address and sends an NTP request to that server | Roadmap | -------------------------------------------------------------------------------- /modules/test/ntp/bin/start_test_module: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # An example startup script that does the bare minimum to start 4 | # a test module via a pyhon script. Each test module should include a 5 | # start_test_module file that overwrites this one to boot all of its 6 | # specific requirements to run. 7 | 8 | # Define where the python source files are located 9 | PYTHON_SRC_DIR=/testrun/python/src 10 | 11 | # Fetch module name 12 | MODULE_NAME=$1 13 | 14 | # Default interface should be veth0 for all containers 15 | DEFAULT_IFACE=veth0 16 | 17 | # Allow a user to define an interface by passing it into this script 18 | DEFINED_IFACE=$2 19 | 20 | # Select which interace to use 21 | if [[ -z $DEFINED_IFACE || "$DEFINED_IFACE" == "null" ]] 22 | then 23 | echo "No interface defined, defaulting to veth0" 24 | INTF=$DEFAULT_IFACE 25 | else 26 | INTF=$DEFINED_IFACE 27 | fi 28 | 29 | # Create and set permissions on the log files 30 | RESULT_FILE=/runtime/output/$MODULE_NAME-result.json 31 | touch $RESULT_FILE 32 | chown $HOST_USER $RESULT_FILE 33 | 34 | # Run the python scrip that will execute the tests for this module 35 | # -u flag allows python print statements 36 | # to be logged by docker by running unbuffered 37 | python3 -u $PYTHON_SRC_DIR/run.py "-m $MODULE_NAME" 38 | 39 | echo Module has finished -------------------------------------------------------------------------------- /modules/test/ntp/conf/module_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "meta": { 4 | "name": "ntp", 5 | "display_name": "NTP", 6 | "description": "NTP test" 7 | }, 8 | "network": false, 9 | "docker": { 10 | "depends_on": "base", 11 | "enable_container": true, 12 | "timeout": 60 13 | }, 14 | "tests":[ 15 | { 16 | "name": "ntp.network.ntp_support", 17 | "test_description": "Does the device request network time sync as client as per RFC 5905 - Network Time Protocol Version 4: Protocol and Algorithms Specification", 18 | "expected_behavior": "The device sends an NTPv4 request to the configured NTP server.", 19 | "recommendations": [ 20 | "Set the NTP version to v4 in the NTP client", 21 | "Install an NTP client that supports NTPv4" 22 | ] 23 | }, 24 | { 25 | "name": "ntp.network.ntp_dhcp", 26 | "test_description": "Accept NTP address over DHCP", 27 | "expected_behavior": "Device can accept NTP server address, provided by the DHCP server (DHCP OFFER PACKET)", 28 | "recommendations": [ 29 | "Install an NTP client that supports fetching the NTP servers from DHCP options" 30 | ] 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /modules/test/ntp/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | 5 | # User defined packages 6 | scapy==2.6.0 7 | pyshark==0.6 8 | -------------------------------------------------------------------------------- /modules/test/ntp/resources/report_template.jinja2: -------------------------------------------------------------------------------- 1 | {% extends base_template %} 2 | {% block content %} 3 | {% if module_data %} 4 | 5 | 6 | 7 | {% for header in module_data_headers %} 8 | 9 | {% endfor %} 10 | 11 | 12 | 13 | {% for row in module_data %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% endfor %} 23 | 24 |
{{ header }}
{{ row['src'] }}{{ row['dst'] }}{{ row['typ'] }}{{ row['version'] }}{{ row['cnt'] }}{{ row['avg_fmt'] }}
25 | {% else %} 26 |
27 |
28 | No NTP traffic detected from the device 29 |
30 | {% endif %} 31 | {% endblock %} -------------------------------------------------------------------------------- /modules/test/protocol/README.md: -------------------------------------------------------------------------------- 1 | # Protocol Test Module 2 | 3 | The protocol test module verifies whether the device communicates using BMS protocols. 4 | 5 | ## What's inside? 6 | 7 | The ```bin``` folder contains the startup script for the module. 8 | 9 | The ```config/module_config.json``` provides the name and description of the module, and specifies which tests will be caried out. 10 | 11 | Within the ```python/src``` directory, the below tests are executed. 12 | 13 | ## Tests covered 14 | 15 | | ID | Description | Expected behavior | Required result 16 | |---|---|---|---| 17 | | protocol.valid_bacnet | Can valid BACnet traffic be seen | BACnet traffic can be seen on the network and packets are valid | Recommended | 18 | | protocol.bacnet.version | Obtain the version of BACnet client used | The BACnet client implements an up to date version of BACnet | Recommended | 19 | | protocol.valid_modbus | Can valid Modbus traffic be seen | Any Modbus functionality works as expected and valid Modbus traffic can be observed | Recommended | -------------------------------------------------------------------------------- /modules/test/protocol/bin/get_bacnet_packets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | CAPTURE_FILE="$1" 18 | OBJECT_ID="$2" 19 | 20 | TSHARK_OUTPUT="-T json -e ip.src -e ip.dst -e eth.src -e eth.dst -e bacapp.instance_number" 21 | TSHARK_FILTER="bacapp.instance_number == $OBJECT_ID" 22 | 23 | response=$(tshark -r "$CAPTURE_FILE" $TSHARK_OUTPUT $TSHARK_FILTER) 24 | 25 | echo "$response" 26 | -------------------------------------------------------------------------------- /modules/test/protocol/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | bacpypes==0.18.7 5 | colorama==0.4.6 6 | 7 | # User defined packages 8 | # Required for BACnet protocol tests 9 | netifaces==0.11.0 10 | BAC0==23.7.3 11 | pytz==2024.2 12 | 13 | # Required for Modbus protocol tests 14 | pymodbus==3.7.4 15 | -------------------------------------------------------------------------------- /modules/test/services/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | 5 | # User defined packages 6 | xmltodict==0.14.2 7 | -------------------------------------------------------------------------------- /modules/test/services/resources/report_template.jinja2: -------------------------------------------------------------------------------- 1 | {% extends base_template %} 2 | {% block content %} 3 | {% if module_data %} 4 | 5 | 6 | 7 | {% for header in module_data_headers %} 8 | 9 | {% endfor %} 10 | 11 | 12 | 13 | {% for row in module_data %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% endfor %} 21 | 22 |
{{ header }}
{{ row['Port'] }}{{ row['State'] }}{{ row['Service'] }}{{ row['Version'] }}
23 | {% else %} 24 |
25 |
26 | No open ports detected 27 |
28 | {% endif %} 29 | {% endblock %} -------------------------------------------------------------------------------- /modules/test/tls/bin/check_cert_chain_signature.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | INTERMEDIATE="$1" 18 | DEVICE_CERT="$2" 19 | 20 | echo "ROOT: $ROOT_CERT" 21 | echo "DEVICE_CERT: $DEVICE_CERT" 22 | 23 | response=$(openssl verify -untrusted "$INTERMEDIATE" "$DEVICE_CERT") 24 | 25 | echo "$response" -------------------------------------------------------------------------------- /modules/test/tls/bin/check_cert_signature.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | ROOT_CERT="$1" 18 | DEVICE_CERT="$2" 19 | 20 | echo "ROOT: $ROOT_CERT" 21 | echo "DEVICE_CERT: $DEVICE_CERT" 22 | 23 | response=$(openssl verify -CAfile "$ROOT_CERT" "$DEVICE_CERT") 24 | 25 | echo "$response" 26 | -------------------------------------------------------------------------------- /modules/test/tls/bin/get_ciphers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | CAPTURE_FILE="$1" 18 | DST_IP="$2" 19 | DST_PORT="$3" 20 | 21 | TSHARK_FILTER="ssl.handshake.ciphersuites and ip.dst==$DST_IP and tcp.dstport==$DST_PORT" 22 | response=$(tshark -r "$CAPTURE_FILE" -Y "$TSHARK_FILTER" -Vx | grep 'Cipher Suite:' | awk '{$1=$1};1' | sed 's/Cipher Suite: //') 23 | 24 | echo "$response" 25 | -------------------------------------------------------------------------------- /modules/test/tls/bin/get_tls_client_connections.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | CAPTURE_FILE="$1" 18 | SRC_MAC="$2" 19 | PROTOCOL=$3 20 | 21 | TSHARK_OUTPUT="-T json -e ip.src -e tcp.dstport -e ip.dst" 22 | TSHARK_FILTER="eth.src == $SRC_MAC and tls" 23 | 24 | # Add a protocol filter if defined 25 | if [ -n "$PROTOCOL" ];then 26 | TSHARK_FILTER="$TSHARK_FILTER and $PROTOCOL" 27 | fi 28 | 29 | response=$(tshark -r "$CAPTURE_FILE" $TSHARK_OUTPUT $TSHARK_FILTER) 30 | 31 | echo "$response" 32 | -------------------------------------------------------------------------------- /modules/test/tls/python/requirements-test.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | 5 | # User defined packages 6 | scapy==2.6.0 7 | -------------------------------------------------------------------------------- /modules/test/tls/python/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies to user defined packages 2 | # Package dependencies should always be defined before the user defined 3 | # packages to prevent auto-upgrades of stable dependencies 4 | appdirs==1.4.4 5 | certifi==2024.8.30 6 | cffi==1.17.1 7 | charset-normalizer==3.3.2 8 | idna==3.8 9 | packaging==24.1 10 | pycparser==2.22 11 | pyshark==0.6 12 | termcolor==2.4.0 13 | urllib3==2.2.2 14 | 15 | # User defined packages 16 | cryptography==44.0.1 17 | pyOpenSSL==24.3.0 18 | lxml==5.1.0 # Requirement of pyshark but if upgraded automatically above 5.1 will cause a 19 | pyshark==0.6 20 | requests==2.32.3 21 | python-nmap==0.7.1 22 | -------------------------------------------------------------------------------- /modules/ui/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /modules/ui/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["projects/**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:@angular-eslint/recommended", 11 | "plugin:@angular-eslint/template/process-inline-templates", 12 | "plugin:prettier/recommended" 13 | ], 14 | "rules": { 15 | "@angular-eslint/directive-selector": [ 16 | "error", 17 | { 18 | "type": "attribute", 19 | "prefix": "app", 20 | "style": "camelCase" 21 | } 22 | ], 23 | "@angular-eslint/component-selector": [ 24 | "error", 25 | { 26 | "type": "element", 27 | "prefix": "app", 28 | "style": "kebab-case" 29 | } 30 | ] 31 | } 32 | }, 33 | { 34 | "files": ["*.html"], 35 | "extends": [ 36 | "plugin:@angular-eslint/template/recommended", 37 | "plugin:@angular-eslint/template/accessibility", 38 | "plugin:prettier/recommended" 39 | ], 40 | "rules": { 41 | "prettier/prettier": [ 42 | "error", 43 | { 44 | "parser": "angular" 45 | } 46 | ] 47 | } 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /modules/ui/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | !.idea/copyright 17 | .project 18 | .classpath 19 | .c9/ 20 | *.launch 21 | .settings/ 22 | *.sublime-workspace 23 | 24 | # Visual Studio Code 25 | .vscode/* 26 | !.vscode/settings.json 27 | !.vscode/tasks.json 28 | !.vscode/launch.json 29 | !.vscode/extensions.json 30 | .history/* 31 | 32 | # Miscellaneous 33 | /.angular/cache 34 | .sass-cache/ 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | testem.log 39 | /typings 40 | 41 | # System files 42 | .DS_Store 43 | Thumbs.db 44 | -------------------------------------------------------------------------------- /modules/ui/.prettierignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | !.idea/copyright 17 | .project 18 | .classpath 19 | .c9/ 20 | *.launch 21 | .settings/ 22 | *.sublime-workspace 23 | 24 | # Visual Studio Code 25 | .vscode/* 26 | !.vscode/settings.json 27 | !.vscode/tasks.json 28 | !.vscode/launch.json 29 | !.vscode/extensions.json 30 | .history/* 31 | 32 | # Miscellaneous 33 | /.angular/cache 34 | .sass-cache/ 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | testem.log 39 | /typings 40 | 41 | # System files 42 | .DS_Store 43 | Thumbs.db 44 | -------------------------------------------------------------------------------- /modules/ui/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | "singleQuote": true, 5 | "semi": true, 6 | "bracketSpacing": true, 7 | "arrowParens": "avoid", 8 | "trailingComma": "es5", 9 | "bracketSameLine": true, 10 | "printWidth": 80, 11 | "endOfLine": "auto" 12 | } 13 | -------------------------------------------------------------------------------- /modules/ui/README.md: -------------------------------------------------------------------------------- 1 | # Testrun UI 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.1.3. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /modules/ui/build.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/build-ui 16 | FROM node@sha256:ffebb4405810c92d267a764b21975fb2d96772e41877248a37bf3abaa0d3b590 as build 17 | 18 | # Set the working directory 19 | WORKDIR /modules/ui -------------------------------------------------------------------------------- /modules/ui/src/app/components/bypass/bypass.component.html: -------------------------------------------------------------------------------- 1 | 16 | 27 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/bypass/bypass.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | :host { 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | display: flex; 21 | z-index: 10; 22 | width: 100%; 23 | } 24 | .navigation-bypass-container { 25 | margin: 0 auto 16px; 26 | box-shadow: 27 | 0 3px 4px 0 rgb(0 0 0 / 14%), 28 | 0 3px 3px -2px rgb(0 0 0 / 12%), 29 | 0 1px 8px 0 rgb(0 0 0 / 20%); 30 | background-color: white; 31 | padding: 0 16px; 32 | overflow: hidden; 33 | display: flex; 34 | &:focus-within .navigation-bypass-button { 35 | max-height: 64px; 36 | margin-top: 16px; 37 | margin-bottom: 16px; 38 | } 39 | } 40 | 41 | .navigation-bypass-button { 42 | max-height: 0; 43 | } 44 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/component-with-announcement.ts: -------------------------------------------------------------------------------- 1 | import { LiveAnnouncer } from '@angular/cdk/a11y'; 2 | import { FocusManagerService } from '../services/focus-manager.service'; 3 | import { timer } from 'rxjs'; 4 | 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 6 | type Constructor = new (...args: any[]) => T; 7 | 8 | export function ComponentWithAnnouncement(base: T) { 9 | return class extends base { 10 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 11 | constructor(...args: any[]) { 12 | const [dialogRef, title, liveAnnouncer, focusService] = args; 13 | super(...args); 14 | 15 | this.focusService = focusService; 16 | 17 | dialogRef.afterOpened().subscribe(() => { 18 | (liveAnnouncer as LiveAnnouncer).clear(); 19 | (liveAnnouncer as LiveAnnouncer) 20 | .announce(title, 'assertive') 21 | .then(() => { 22 | timer(200).subscribe(() => { 23 | this.focusService.focusFirstElementInContainer(); 24 | }); 25 | }); 26 | }); 27 | 28 | dialogRef.beforeClosed().subscribe(() => { 29 | (liveAnnouncer as LiveAnnouncer).clear(); 30 | }); 31 | } 32 | 33 | focusService!: FocusManagerService; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/device-tests/device-tests.component.html: -------------------------------------------------------------------------------- 1 | 16 |
17 |

Test modules

18 |

19 | All modules are required to pass for qualification 20 |

21 |
22 |

25 | 26 | {{ testModules[i].displayName }} 27 | 28 |

29 |
30 |
31 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/device-tests/device-tests.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @use 'colors'; 17 | @use 'variables'; 18 | @use 'mixins'; 19 | 20 | .device-tests-form { 21 | height: 100%; 22 | display: grid; 23 | grid-template-rows: repeat(3, auto); 24 | } 25 | 26 | .disabled { 27 | @include mixins.disabled; 28 | } 29 | 30 | .device-tests-title { 31 | margin: 20px 0 8px; 32 | font-size: 18px; 33 | line-height: 24px; 34 | color: colors.$on-surface-variant; 35 | } 36 | 37 | .device-tests-description { 38 | margin: 0; 39 | font-family: variables.$font-text; 40 | font-size: 14px; 41 | line-height: 20px; 42 | letter-spacing: 0.2px; 43 | color: colors.$on-surface-variant; 44 | } 45 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/download-report-pdf/download-report-pdf.component.html: -------------------------------------------------------------------------------- 1 | 16 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/download-report-pdf/download-report-pdf.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { ChangeDetectionStrategy, Component } from '@angular/core'; 17 | import { CommonModule, DatePipe } from '@angular/common'; 18 | import { DownloadReportComponent } from '../download-report/download-report.component'; 19 | import { ReportActionComponent } from '../report-action/report-action.component'; 20 | 21 | @Component({ 22 | selector: 'app-download-report-pdf', 23 | templateUrl: './download-report-pdf.component.html', 24 | 25 | imports: [CommonModule, DownloadReportComponent], 26 | providers: [DatePipe], 27 | changeDetection: ChangeDetectionStrategy.OnPush, 28 | }) 29 | export class DownloadReportPdfComponent extends ReportActionComponent {} 30 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/download-report-zip/download-report-zip.component.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/download-report-zip/download-report-zip.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | :host { 17 | cursor: pointer; 18 | } 19 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/download-report/download-report.component.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/download-report/download-report.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @use 'mixins'; 17 | 18 | :host { 19 | display: inline-block; 20 | } 21 | 22 | .download-report-link { 23 | @include mixins.report-action; 24 | } 25 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/empty-message/empty-message.component.html: -------------------------------------------------------------------------------- 1 | 16 |
19 |
20 | empty message image 21 |
22 | 23 | {{ header() }} 24 | {{ message() }} 25 | {{ messageNext() }} 26 | 27 | 28 |
29 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/empty-message/empty-message.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { Component, input } from '@angular/core'; 17 | import { CommonModule } from '@angular/common'; 18 | 19 | @Component({ 20 | selector: 'app-empty-message', 21 | imports: [CommonModule], 22 | templateUrl: './empty-message.component.html', 23 | styleUrl: './empty-message.component.scss', 24 | }) 25 | export class EmptyMessageComponent { 26 | image = input(); 27 | header = input(); 28 | message = input(); 29 | messageNext = input(); 30 | isHorizontal = input(false); 31 | } 32 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/empty-page/empty-page.component.html: -------------------------------------------------------------------------------- 1 | 16 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/empty-page/empty-page.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { Component, input } from '@angular/core'; 17 | import { EmptyMessageComponent } from '../empty-message/empty-message.component'; 18 | 19 | @Component({ 20 | selector: 'app-empty-page', 21 | imports: [EmptyMessageComponent], 22 | templateUrl: './empty-page.component.html', 23 | }) 24 | export class EmptyPageComponent { 25 | image = input(); 26 | header = input(); 27 | message = input(); 28 | messageNext = input(); 29 | } 30 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/list-item/list-item.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @use 'variables'; 17 | @use 'colors'; 18 | @use '@angular/material' as mat; 19 | 20 | ::ng-deep { 21 | .list-item-menu { 22 | width: 220px; 23 | } 24 | } 25 | 26 | .list-item { 27 | border-radius: variables.$corner-large; 28 | background-color: colors.$surface-container; 29 | height: 92px; 30 | padding: 0 24px 0 32px; 31 | display: grid; 32 | grid-template-columns: auto 40px; 33 | align-items: center; 34 | &.disabled { 35 | cursor: not-allowed; 36 | } 37 | } 38 | 39 | .example-menu { 40 | left: 12px; 41 | } 42 | 43 | .list-item-menu-item { 44 | padding: 16px 24px; 45 | &.cdk-mouse-focused::before { 46 | content: none; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/no-entity-selected/no-entity-selected.component.html: -------------------------------------------------------------------------------- 1 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/no-entity-selected/no-entity-selected.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { Component, input } from '@angular/core'; 17 | import { EmptyMessageComponent } from '../empty-message/empty-message.component'; 18 | @Component({ 19 | selector: 'app-no-entity-selected', 20 | imports: [EmptyMessageComponent], 21 | templateUrl: './no-entity-selected.component.html', 22 | styleUrl: './no-entity-selected.component.scss', 23 | }) 24 | export class NoEntitySelectedComponent { 25 | image = input(); 26 | header = input(); 27 | message = input(); 28 | } 29 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/program-type-icon/program-type-icon.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { Component, Input } from '@angular/core'; 17 | import { MatIcon } from '@angular/material/icon'; 18 | 19 | @Component({ 20 | selector: 'app-program-type-icon', 21 | 22 | imports: [MatIcon], 23 | template: ` `, 24 | styles: ` 25 | :host { 26 | display: inline-flex; 27 | align-items: center; 28 | } 29 | .icon { 30 | display: flex; 31 | line-height: 16px; 32 | } 33 | `, 34 | }) 35 | export class ProgramTypeIconComponent { 36 | @Input() type = ''; 37 | } 38 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/report-action/report-action.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChangeDetectionStrategy, 3 | Component, 4 | Input, 5 | inject, 6 | } from '@angular/core'; 7 | import { CommonModule, DatePipe } from '@angular/common'; 8 | import { TestrunStatus } from '../../model/testrun-status'; 9 | 10 | @Component({ 11 | selector: 'app-report-action', 12 | 13 | imports: [CommonModule], 14 | template: '', 15 | providers: [DatePipe], 16 | changeDetection: ChangeDetectionStrategy.OnPush, 17 | }) 18 | export class ReportActionComponent { 19 | private datePipe = inject(DatePipe); 20 | 21 | @Input() data!: TestrunStatus; 22 | 23 | getTestRunId(data: TestrunStatus) { 24 | if (!data.device) { 25 | return ''; 26 | } 27 | return `${data.device.manufacturer} ${data.device.model} ${ 28 | data.device.firmware 29 | } ${this.getFormattedDateString(data.started)}`; 30 | } 31 | 32 | getFormattedDateString(date: string | null) { 33 | return date ? this.datePipe.transform(date, 'd MMM y H:mm') : ''; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/shutdown-app/shutdown-app.component.html: -------------------------------------------------------------------------------- 1 | 16 | 25 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/side-button-menu/side-button-menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input, viewChild } from '@angular/core'; 2 | import { MatButtonModule } from '@angular/material/button'; 3 | import { MatIconModule } from '@angular/material/icon'; 4 | import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu'; 5 | import { CommonModule } from '@angular/common'; 6 | import { AddMenuItem } from '../../app.component'; 7 | import { MatTooltip } from '@angular/material/tooltip'; 8 | 9 | @Component({ 10 | selector: 'app-side-button-menu', 11 | imports: [ 12 | MatButtonModule, 13 | MatIconModule, 14 | MatMenuModule, 15 | CommonModule, 16 | MatTooltip, 17 | ], 18 | templateUrl: './side-button-menu.component.html', 19 | styleUrl: './side-button-menu.component.scss', 20 | }) 21 | export class SideButtonMenuComponent { 22 | readonly menuTrigger = viewChild.required('menuTrigger'); 23 | menuItems = input([]); 24 | 25 | focusButton(event: Event) { 26 | event.preventDefault(); 27 | event.stopPropagation(); 28 | const button = document.querySelector( 29 | '.side-add-button' 30 | ) as HTMLButtonElement; 31 | if (button) { 32 | button.focus(); 33 | } 34 | this.menuTrigger().closeMenu(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/snack-bar/snack-bar.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @use 'colors'; 17 | @use 'variables'; 18 | 19 | .snack-bar-container { 20 | display: flex; 21 | 22 | .snack-bar-label p { 23 | margin: 0; 24 | } 25 | 26 | .snack-bar-actions button.action-btn.stop { 27 | font-family: variables.$font-text; 28 | color: colors.$inverse-primary; 29 | font-weight: 500; 30 | line-height: 20px; 31 | letter-spacing: 0.25px; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/spinner/spinner.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/spinner/spinner.component.scss: -------------------------------------------------------------------------------- 1 | @use '@angular/material' as mat; 2 | @use 'm3-theme' as *; 3 | @use 'colors'; 4 | 5 | .spinner-container { 6 | position: absolute; 7 | width: 100%; 8 | left: 0; 9 | right: 0; 10 | top: 0; 11 | bottom: 0; 12 | background-color: rgba(255, 255, 255, 0.7); 13 | z-index: 2; 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | } 18 | 19 | ::ng-deep { 20 | .loader { 21 | width: 36px; 22 | height: 36px; 23 | border: 4px solid mat.get-theme-color($light-theme, primary, 40); 24 | border-bottom-color: transparent; 25 | border-radius: 50%; 26 | display: inline-block; 27 | box-sizing: border-box; 28 | animation: rotation 1s linear infinite; 29 | } 30 | 31 | @keyframes rotation { 32 | 0% { 33 | transform: rotate(0deg); 34 | } 35 | 100% { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/spinner/spinner.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, inject } from '@angular/core'; 2 | import { LoaderService } from '../../services/loader.service'; 3 | import { CommonModule } from '@angular/common'; 4 | import { Observable } from 'rxjs/internal/Observable'; 5 | 6 | @Component({ 7 | selector: 'app-spinner', 8 | templateUrl: './spinner.component.html', 9 | styleUrls: ['./spinner.component.scss'], 10 | 11 | imports: [CommonModule], 12 | }) 13 | export class SpinnerComponent implements OnInit { 14 | loaderService = inject(LoaderService); 15 | 16 | loader$!: Observable; 17 | 18 | ngOnInit() { 19 | this.loader$ = this.loaderService.getLoading(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/version/version.component.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 32 | 33 | -------------------------------------------------------------------------------- /modules/ui/src/app/components/wifi/wifi.component.html: -------------------------------------------------------------------------------- 1 | 16 | 26 | -------------------------------------------------------------------------------- /modules/ui/src/app/guards/can-deactivate.guard.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { TestBed } from '@angular/core/testing'; 17 | 18 | import { CanDeactivateGuard } from './can-deactivate.guard'; 19 | 20 | describe('CanDeactivateGuard', () => { 21 | let guard: CanDeactivateGuard; 22 | 23 | beforeEach(() => { 24 | TestBed.configureTestingModule({}); 25 | guard = TestBed.inject(CanDeactivateGuard); 26 | }); 27 | 28 | it('should be created', () => { 29 | expect(guard).toBeTruthy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /modules/ui/src/app/mocks/topic.mock.ts: -------------------------------------------------------------------------------- 1 | import { InternetConnection } from '../model/topic'; 2 | 3 | export const MOCK_INTERNET: InternetConnection = { 4 | connection: false, 5 | }; 6 | -------------------------------------------------------------------------------- /modules/ui/src/app/mocks/version.mock.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export const VERSION = { 17 | installed_version: 'v1', 18 | latest_version: 'v1', 19 | latest_version_url: '', 20 | update_available: false, 21 | }; 22 | 23 | export const NEW_VERSION = { 24 | installed_version: 'v1', 25 | latest_version: 'v2', 26 | latest_version_url: 'test-url', 27 | update_available: true, 28 | }; 29 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/callout-type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export enum CalloutType { 17 | Info = 'info', 18 | InfoPilot = 'info pilot', 19 | Check = 'check_circle', 20 | Warning = 'warning', 21 | Error = 'error', 22 | } 23 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/certificate.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export interface Certificate { 17 | name: string; 18 | status?: CertificateStatus; 19 | organisation?: string; 20 | expires?: string; 21 | uploading?: boolean; 22 | } 23 | 24 | export enum CertificateStatus { 25 | Valid = 'Valid', 26 | Expired = 'Expired', 27 | } 28 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/entity-action.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export interface EntityAction { 17 | action: string; 18 | icon?: string; 19 | svgIcon?: string; 20 | } 21 | 22 | export interface EntityActionResult { 23 | action: string; 24 | entity: T; 25 | index: number; 26 | } 27 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/event-type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export enum EventType { 17 | Close = 'Close event', 18 | Save = 'Save event', 19 | } 20 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/layout-type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export enum LayoutType { 18 | Device = 'Devices', 19 | Profile = 'Risk Assessment', 20 | } 21 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/program-type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export enum ProgramType { 17 | Pilot = 'pilot', 18 | Qualification = 'qualification', 19 | } 20 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/question.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export interface Validation { 17 | required: boolean | undefined; 18 | max?: string; 19 | } 20 | 21 | export enum FormControlType { 22 | SELECT = 'select', 23 | TEXTAREA = 'text-long', 24 | EMAIL_MULTIPLE = 'email-multiple', 25 | SELECT_MULTIPLE = 'select-multiple', 26 | TEXT = 'text', 27 | } 28 | 29 | export interface QuestionFormat { 30 | question: string; 31 | type: FormControlType; 32 | description?: string; 33 | options?: OptionType[]; 34 | default?: string; 35 | validation?: Validation; 36 | } 37 | 38 | export type OptionType = string | object; 39 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/routes.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export enum Routes { 18 | Devices = '/devices', 19 | Settings = '/settings', 20 | Testing = '/testing', 21 | Reports = '/reports', 22 | RiskAssessment = '/risk-assessment', 23 | Certificates = 'certificates', 24 | General = 'general', 25 | } 26 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/topic.ts: -------------------------------------------------------------------------------- 1 | export enum Topic { 2 | NetworkAdapters = 'events/adapter', 3 | InternetConnection = 'events/internet', 4 | Status = 'status', 5 | } 6 | 7 | export interface InternetConnection { 8 | connection: boolean | null; 9 | } 10 | -------------------------------------------------------------------------------- /modules/ui/src/app/model/version.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export interface Version { 18 | installed_version: string; 19 | update_available: boolean; 20 | latest_version: string; 21 | latest_version_url: string; 22 | } 23 | 24 | export interface ConsentDialogResult { 25 | grant: boolean; 26 | } 27 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/certificates/certificates.component.html: -------------------------------------------------------------------------------- 1 | 16 |
17 | 19 |
20 |
21 | 27 | 28 |
29 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/certificates/certificates.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @use '@angular/material' as mat; 17 | @use 'colors'; 18 | @use 'variables'; 19 | 20 | :host { 21 | display: flex; 22 | flex-direction: column; 23 | flex: 1 0 auto; 24 | } 25 | 26 | .content-certificates { 27 | margin: 2px 18px 0; 28 | height: max-content; 29 | padding: 0 6px 6px; 30 | } 31 | 32 | .certificates-button-container { 33 | margin: 24px; 34 | } 35 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/certificates/components/certificate-upload-button/certificate-upload-button.component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/certificates/components/certificate-upload-button/certificate-upload-button.component.scss: -------------------------------------------------------------------------------- 1 | @use 'colors'; 2 | @use 'variables'; 3 | 4 | .browse-files-button { 5 | border-radius: 16px; 6 | padding: 16px 24px; 7 | font-family: variables.$font-text; 8 | font-size: 16px; 9 | font-weight: 500; 10 | line-height: 24px; 11 | letter-spacing: 0.25px; 12 | height: auto; 13 | background: colors.$secondary-container; 14 | color: colors.$on-secondary-container; 15 | } 16 | 17 | #default-file-input { 18 | display: none; 19 | } 20 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/certificates/components/certificate-upload-button/certificate-upload-button.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Output } from '@angular/core'; 2 | import { MatButtonModule } from '@angular/material/button'; 3 | 4 | @Component({ 5 | selector: 'app-certificate-upload-button', 6 | 7 | imports: [MatButtonModule], 8 | templateUrl: './certificate-upload-button.component.html', 9 | styleUrl: './certificate-upload-button.component.scss', 10 | }) 11 | export class CertificateUploadButtonComponent { 12 | @Output() fileChanged = new EventEmitter(); 13 | fileChange(event: Event) { 14 | const input = event.target as HTMLInputElement; 15 | const fileList = input.files; 16 | if (fileList && fileList.length < 1) { 17 | return; 18 | } 19 | 20 | // @ts-expect-error fileList is not null at this point 21 | const file: File = fileList[0]; 22 | 23 | this.fileChanged.emit(file); 24 | input.value = ''; 25 | input.dispatchEvent(new Event('change')); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/devices/devices.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @use 'mixins'; 17 | 18 | .device-add-button { 19 | @include mixins.add-button; 20 | } 21 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/reports/components/delete-report/delete-report.component.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/reports/components/delete-report/delete-report.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @use 'mixins'; 17 | 18 | :host { 19 | display: inline-block; 20 | } 21 | 22 | .delete-report-button { 23 | @include mixins.report-action; 24 | } 25 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/reports/components/filter-header/filter-header.component.html: -------------------------------------------------------------------------------- 1 | 5 | {{ headerText }} 6 | 16 | 17 | 18 | 19 | 25 | 38 | 39 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/reports/components/filter-header/filter-header.component.scss: -------------------------------------------------------------------------------- 1 | @use 'node_modules/@angular/material/index' as mat; 2 | @use 'src/theming/m3-theme' as *; 3 | @use 'colors'; 4 | @use 'variables'; 5 | 6 | :host { 7 | display: contents; 8 | } 9 | 10 | th { 11 | height: var(--mat-table-header-container-height); 12 | vertical-align: middle; 13 | } 14 | 15 | .filter-button { 16 | display: flex; 17 | width: variables.$reports-table-header-size; 18 | height: variables.$reports-table-header-size; 19 | justify-content: center; 20 | align-items: center; 21 | flex-shrink: 0; 22 | margin-left: 8px; 23 | padding: 0; 24 | border: none; 25 | background: colors.$white; 26 | cursor: pointer; 27 | border-radius: 50%; 28 | &:hover { 29 | background-color: rgba(0, 0, 0, 0.04); 30 | } 31 | &:active, 32 | &.active { 33 | background-color: colors.$secondary-container; 34 | color: colors.$on-secondary-container; 35 | &:hover { 36 | filter: brightness(90%); 37 | } 38 | } 39 | } 40 | 41 | .filter-button.active .mat-icon { 42 | color: mat.get-theme-color($light-theme, primary, 35); 43 | } 44 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/risk-assessment/risk-assessment.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @use 'colors'; 17 | @use 'variables'; 18 | @use 'mixins'; 19 | 20 | :host { 21 | overflow: auto; 22 | } 23 | 24 | .risk-assessment-add-button { 25 | @include mixins.add-button; 26 | } 27 | 28 | .risk-assessment-content-empty { 29 | @include mixins.content-empty; 30 | } 31 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/settings/settings.component.html: -------------------------------------------------------------------------------- 1 | 16 | 17 |

Settings

18 |
19 | 20 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /modules/ui/src/app/pages/settings/settings.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | :host { 18 | overflow: auto; 19 | } 20 | 21 | .toolbar { 22 | height: auto; 23 | padding: 22px 0px 18px 32px; 24 | } 25 | .title { 26 | padding: 24px 0 16px; 27 | } 28 | 29 | .tab-item { 30 | display: flex; 31 | padding: 0px 32px; 32 | align-items: center; 33 | gap: 32px; 34 | } 35 | .tab-group { 36 | ::ng-deep .mat-mdc-tab-labels { 37 | gap: 16px; 38 | padding: 0 12px; 39 | } 40 | 41 | ::ng-deep.mat-mdc-tab { 42 | padding: 0px 8px; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /modules/ui/src/app/providers/window.provider.ts: -------------------------------------------------------------------------------- 1 | import { FactoryProvider, InjectionToken } from '@angular/core'; 2 | 3 | /** 4 | * Copyright 2023 Google LLC 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * https://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | export const WINDOW = new InjectionToken('window'); 19 | 20 | export const WindowProvider: FactoryProvider = { 21 | provide: WINDOW, 22 | useFactory: getWindow, 23 | }; 24 | 25 | export function getWindow(): Window { 26 | return window; 27 | } 28 | -------------------------------------------------------------------------------- /modules/ui/src/app/services/focus-manager.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root', 5 | }) 6 | export class FocusManagerService { 7 | focusFirstElementInContainer( 8 | container: Document | Element | null = window.document.querySelector( 9 | '#main' 10 | ) 11 | ) { 12 | const dialogOpened = window.document.querySelector('.mdc-dialog--open'); 13 | const parentElem = dialogOpened ? dialogOpened : container; 14 | const firstInteractiveElem = this.findFirstInteractiveElem(parentElem); 15 | if (firstInteractiveElem) { 16 | firstInteractiveElem.focus(); 17 | } 18 | } 19 | 20 | private findFirstInteractiveElem( 21 | parentEl: Document | Element | null 22 | ): HTMLElement | undefined | null { 23 | return parentEl?.querySelector( 24 | 'button:not([disabled="true"]):not([tabindex="-1"]), a:not([disabled="true"]), input:not([disabled="true"]), table, [tabindex="0"]' 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /modules/ui/src/app/services/loader.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { fakeAsync, TestBed, tick } from '@angular/core/testing'; 2 | 3 | import { LoaderService } from './loader.service'; 4 | 5 | describe('LoaderService', () => { 6 | let service: LoaderService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(LoaderService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | 17 | describe('update loading value', () => { 18 | it('should has delay if true', fakeAsync(() => { 19 | service.setLoading(true); 20 | 21 | const timeoutSpy = jasmine.createSpy('timeoutSpy'); 22 | service.getLoading().subscribe(timeoutSpy); 23 | 24 | expect(timeoutSpy).not.toHaveBeenCalled(); 25 | tick(1000); 26 | expect(timeoutSpy).toHaveBeenCalledWith(true); 27 | })); 28 | 29 | it('should has no delay if false', fakeAsync(() => { 30 | service.setLoading(false); 31 | 32 | const timeoutSpy = jasmine.createSpy('timeoutSpy'); 33 | service.getLoading().subscribe(timeoutSpy); 34 | 35 | expect(timeoutSpy).toHaveBeenCalledWith(false); 36 | })); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /modules/ui/src/app/services/loader.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, inject } from '@angular/core'; 2 | import { BehaviorSubject, delay, Observable, of, switchMap } from 'rxjs'; 3 | import { LOADER_TIMEOUT_CONFIG_TOKEN } from './loaderConfig'; 4 | 5 | @Injectable({ 6 | providedIn: 'root', 7 | }) 8 | export class LoaderService { 9 | private timeout = 10 | inject(LOADER_TIMEOUT_CONFIG_TOKEN, { optional: true }) ?? 1000; 11 | 12 | private loading$ = new BehaviorSubject(false); 13 | 14 | setLoading(loading: boolean) { 15 | this.loading$.next(loading); 16 | } 17 | 18 | getLoading(): Observable { 19 | return this.loading$.pipe( 20 | switchMap(loading => { 21 | if (loading) { 22 | return of(true).pipe(delay(this.timeout)); 23 | } 24 | return of(false); 25 | }) 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /modules/ui/src/app/services/loaderConfig.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { InjectionToken } from '@angular/core'; 17 | 18 | export const LOADER_TIMEOUT_CONFIG_TOKEN = new InjectionToken( 19 | 'loaderTimeoutConfig' 20 | ); 21 | -------------------------------------------------------------------------------- /modules/ui/src/app/services/local-storage.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root', 5 | }) 6 | export class LocalStorageService { 7 | private readonly GA_CONSENT_KEY = 'GA_CONSENT'; 8 | 9 | getGAConsent() { 10 | const consent = this.getItem(this.GA_CONSENT_KEY); 11 | return consent !== null ? consent === 'true' : true; 12 | } 13 | 14 | setGAConsent(value: boolean) { 15 | this.setItem(this.GA_CONSENT_KEY, value); 16 | } 17 | 18 | private getItem(key: string) { 19 | return localStorage.getItem(key); 20 | } 21 | 22 | private setItem(key: string, value: unknown) { 23 | localStorage.setItem(key, String(value)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /modules/ui/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/modules/ui/src/assets/.gitkeep -------------------------------------------------------------------------------- /modules/ui/src/assets/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /modules/ui/src/assets/icons/draft.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /modules/ui/src/assets/icons/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /modules/ui/src/assets/icons/qualification.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /modules/ui/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/modules/ui/src/favicon.ico -------------------------------------------------------------------------------- /modules/ui/src/theming/variables.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | $device-item-width: 100%; 17 | $profiles-drawer-width: 320px; 18 | $form-max-width: 732px; 19 | $icon-size: 24px; 20 | $corner-large: 16px; 21 | $corner-extra-large: 28px; 22 | $corner-extra-extra-large: 48px; 23 | $corner-medium: 12px; 24 | $reports-table-header-size: 32px; 25 | 26 | // nav variables 27 | $nav-button-height: 32px; 28 | 29 | $font-primary: 'Google Sans', sans-serif; 30 | $font-secondary: 'Roboto', sans-serif; 31 | $font-text: 'Google Sans Text', sans-serif; 32 | $font-symbols: 'Google Symbols'; 33 | -------------------------------------------------------------------------------- /modules/ui/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": ["src/main.ts"], 9 | "include": ["src/**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /modules/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "lib": ["ES2022", "dom"] 23 | }, 24 | "angularCompilerOptions": { 25 | "enableI18nLegacyMessageIdFormat": false, 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /modules/ui/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": ["jasmine"] 7 | }, 8 | "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /modules/ui/ui.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Image name: testrun/ui 16 | FROM nginx@sha256:4c0fdaa8b6341bfdeca5f18f7837462c80cff90527ee35ef185571e1c327beac 17 | 18 | COPY modules/ui/dist/ /usr/share/nginx/html 19 | 20 | EXPOSE 8080 21 | 22 | CMD ["nginx", "-g", "daemon off;"] 23 | -------------------------------------------------------------------------------- /modules/ws/conf/mosquitto.conf: -------------------------------------------------------------------------------- 1 | ## Logging 2 | 3 | log_dest stdout 4 | log_type all 5 | log_timestamp true 6 | connection_messages false 7 | 8 | ## MQTT Listener 9 | 10 | listener 1883 11 | protocol mqtt 12 | 13 | ## WebSockets Listener 14 | 15 | listener 9001 16 | protocol websockets 17 | 18 | allow_anonymous true 19 | 20 | ## Persistence 21 | 22 | persistence false -------------------------------------------------------------------------------- /modules/ws/ws.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-mosquitto@sha256:4a46c840adf48e7acd49883206a5c075c14ec95845ee6d30ba935a6719d6b41c 2 | RUN mkdir -p /mosquitto/data/ 3 | COPY modules/ws/conf/mosquitto.conf /mosquitto/config/mosquitto.conf 4 | VOLUME /mosquitto/data/ -------------------------------------------------------------------------------- /resources/devices/template/device_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "manufacturer": "Manufacturer X", 3 | "model": "Device X", 4 | "mac_addr": "aa:bb:cc:dd:ee:ff", 5 | "max_device_tests": 0, 6 | "test_modules": { 7 | "dns": { 8 | "enabled": true 9 | }, 10 | "connection": { 11 | "enabled": true 12 | }, 13 | "ntp": { 14 | "enabled": true 15 | }, 16 | "baseline": { 17 | "enabled": false 18 | }, 19 | "services": { 20 | "enabled": true 21 | }, 22 | "tls": { 23 | "enabled": true 24 | }, 25 | "protocol": { 26 | "enabled": false 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /resources/report/Google Sans.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/resources/report/Google Sans.woff2 -------------------------------------------------------------------------------- /resources/report/testrun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/resources/report/testrun.png -------------------------------------------------------------------------------- /resources/test_packs/pilot/report_templates/device_profile.jinja: -------------------------------------------------------------------------------- 1 | {% macro insert(device_profile) %} 2 |

Device profile

3 |
4 |
5 |
Question
6 |
Answer
7 |
8 | {% for question in device_profile %} 9 |
10 |
{{loop.index}}.
11 |
{{ question['question'] }}
12 |
13 | {% if question['answer'] is string %} 14 | {{ question['answer'] }} 15 | {% elif question['answer'] is sequence %} 16 |
    17 | {% for answer in question['answer'] %} 18 |
  • {{ answer }}
  • 19 | {% endfor %} 20 |
21 | {% endif %} 22 |
23 |
24 | {% endfor %} 25 |
26 | {% endmacro %} -------------------------------------------------------------------------------- /resources/test_packs/pilot/report_templates/header.jinja: -------------------------------------------------------------------------------- 1 | {% macro insert(is_first, device, logo, icon) %} 2 | {% if is_first %} 3 |
4 |
5 | {# Badge #} 6 |

7 | 8 | Pilot Assessment 9 |

10 |

Testrun report

11 |
12 |

13 | {{ device['manufacturer'] }} 14 | {{ device['model']}} 15 |

16 | {% else %} 17 |
18 |
19 | {# Badge #} 20 |

21 | 22 | Pilot Assessment 23 |

24 | Testrun report 25 |
26 | 27 | {{ device['manufacturer'] }} 28 | {{ device['model']}} 29 | 30 | {% endif %} 31 | Testrun 32 |
33 | {% endmacro %} -------------------------------------------------------------------------------- /resources/test_packs/pilot/report_templates/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/resources/test_packs/pilot/report_templates/icon.png -------------------------------------------------------------------------------- /resources/test_packs/pilot/report_templates/resolve_steps.jinja: -------------------------------------------------------------------------------- 1 | {% macro insert(step_index, line) %} 2 |
3 |
4 | {{ step_index }}. 5 |
6 | Name
{{ line['name'] }} 7 |
8 |
9 | Description
{{ line["description"] }} 10 |
11 |
12 |
13 | Steps to resolve 14 | {% for recommedtation in line['recommendations'] %} 15 |
{{ loop.index }}. {{ recommedtation }} 16 | {% endfor %} 17 |
18 |
19 | {% endmacro %} -------------------------------------------------------------------------------- /resources/test_packs/qualification/report_templates/device_profile.jinja: -------------------------------------------------------------------------------- 1 | {% macro insert(device_profile) %} 2 |

Device profile

3 |
4 |
5 |
Question
6 |
Answer
7 |
8 | {% for question in device_profile %} 9 |
10 |
{{loop.index}}.
11 |
{{ question['question'] }}
12 |
13 | {% if question['answer'] is string %} 14 | {{ question['answer'] }} 15 | {% elif question['answer'] is sequence %} 16 |
    17 | {% for answer in question['answer'] %} 18 |
  • {{ answer }}
  • 19 | {% endfor %} 20 |
21 | {% endif %} 22 |
23 |
24 | {% endfor %} 25 |
26 | {% endmacro %} -------------------------------------------------------------------------------- /resources/test_packs/qualification/report_templates/header.jinja: -------------------------------------------------------------------------------- 1 | {% macro insert(is_first, device, logo, icon) %} 2 | {% if is_first %} 3 |
4 |
5 | {# Badge #} 6 |

7 | 8 | Device Qualification 9 |

10 |

Testrun report

11 |
12 |

13 | {{ device['manufacturer'] }} 14 | {{ device['model']}} 15 |

16 | {% else %} 17 |
18 |
19 | {# Badge #} 20 |

21 | 22 | Device Qualification 23 |

24 | Testrun report 25 |
26 | 27 | {{ device['manufacturer'] }} 28 | {{ device['model']}} 29 | 30 | {% endif %} 31 | Testrun 32 |
33 | {% endmacro %} -------------------------------------------------------------------------------- /resources/test_packs/qualification/report_templates/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/resources/test_packs/qualification/report_templates/icon.png -------------------------------------------------------------------------------- /resources/test_packs/qualification/report_templates/resolve_steps.jinja: -------------------------------------------------------------------------------- 1 | {% macro insert(step_index, line) %} 2 |
3 |
4 | {{ step_index }}. 5 |
6 | Name
{{ line['name'] }} 7 |
8 |
9 | Description
{{ line["description"] }} 10 |
11 |
12 |
13 | Steps to resolve 14 | {% for recommedtation in line['recommendations'] %} 15 |
{{ loop.index }}. {{ recommedtation }} 16 | {% endfor %} 17 |
18 |
19 | {% endmacro %} -------------------------------------------------------------------------------- /testing/api/certificates/invalid.pem: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /testing/api/mockito/get_devices.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "mac_addr": "00:1e:42:35:73:c4", 4 | "manufacturer": "Teltonika", 5 | "model": "TRB 140", 6 | "test_modules": { 7 | "dns": { 8 | "enabled": false 9 | }, 10 | "connection": { 11 | "enabled": true 12 | }, 13 | "ntp": { 14 | "enabled": false 15 | }, 16 | "baseline": { 17 | "enabled": false 18 | }, 19 | "nmap": { 20 | "enabled": false 21 | } 22 | } 23 | }, 24 | { 25 | "mac_addr": "aa:bb:cc:dd:ee:ff", 26 | "manufacturer": "Manufacturer X", 27 | "model": "Device X", 28 | "test_modules": { 29 | "dns": { 30 | "enabled": true 31 | }, 32 | "connection": { 33 | "enabled": true 34 | }, 35 | "ntp": { 36 | "enabled": true 37 | }, 38 | "baseline": { 39 | "enabled": false 40 | }, 41 | "nmap": { 42 | "enabled": true 43 | } 44 | } 45 | } 46 | ] -------------------------------------------------------------------------------- /testing/api/mockito/invalid_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "detail": "Not Found" 3 | } -------------------------------------------------------------------------------- /testing/api/mockito/running_system_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "In Progress", 3 | "device": { 4 | "manufacturer": "Delta", 5 | "model": "03-DIN-CPU", 6 | "mac_addr": "01:02:03:04:05:06", 7 | "firmware": "1.2.2" 8 | }, 9 | "started": "2023-06-22T09:20:00.123Z", 10 | "finished": null, 11 | "tests": { 12 | "total": 26, 13 | "results": [ 14 | { 15 | "name": "dns.network.hostname_resolution", 16 | "description": "The device should resolve hostnames", 17 | "result": "Compliant" 18 | }, 19 | { 20 | "name": "dns.network.from_dhcp", 21 | "description": "The device should use the DNS server provided by the DHCP server", 22 | "result": "Non-Compliant" 23 | } 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /testing/api/profiles/draft_profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "draft_profile", 3 | "version": "1.4", 4 | "created": "2024-09-03", 5 | "questions": [ 6 | { 7 | "question": "How will this device be used at Google?", 8 | "answer": "Monitoring" 9 | }, 10 | { 11 | "question": "Is this device going to be managed by Google or a third party?", 12 | "answer": "Google" 13 | }, 14 | { 15 | "question": "Will the third-party device administrator be able to grant access to authorized Google personnel upon request?", 16 | "answer": "" 17 | }, 18 | { 19 | "question": "Which of the following statements are true about this device?", 20 | "answer": [] 21 | }, 22 | { 23 | "question": "Does the network protocol assure server-to-client identity verification?", 24 | "answer": "Yes" 25 | }, 26 | { 27 | "question": "Click the statements that best describe the characteristics of this device.", 28 | "answer": [] 29 | }, 30 | { 31 | "question": "Are any of the following statements true about this device?", 32 | "answer": [] 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /testing/api/profiles/invalid_name.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<>?/:;@''][=^!", 3 | "version": "1.4", 4 | "created": "2024-09-03", 5 | "questions": [ 6 | { 7 | "question": "How will this device be used at Google?", 8 | "answer": "Monitoring" 9 | }, 10 | { 11 | "question": "Is this device going to be managed by Google or a third party?", 12 | "answer": "Google" 13 | }, 14 | { 15 | "question": "Will the third-party device administrator be able to grant access to authorized Google personnel upon request?", 16 | "answer": "N/A" 17 | }, 18 | { 19 | "question": "Which of the following statements are true about this device?", 20 | "answer": [0] 21 | }, 22 | { 23 | "question": "Does the network protocol assure server-to-client identity verification?", 24 | "answer": "Yes" 25 | }, 26 | { 27 | "question": "Click the statements that best describe the characteristics of this device.", 28 | "answer": [0] 29 | }, 30 | { 31 | "question": "Are any of the following statements true about this device?", 32 | "answer": [0] 33 | }, 34 | { 35 | "question": "Comments", 36 | "answer": "" 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /testing/api/profiles/valid_profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "valid_profile", 3 | "version": "1.4", 4 | "created": "2024-09-03", 5 | "questions": [ 6 | { 7 | "question": "How will this device be used at Google?", 8 | "answer": "Monitoring" 9 | }, 10 | { 11 | "question": "Is this device going to be managed by Google or a third party?", 12 | "answer": "Google" 13 | }, 14 | { 15 | "question": "Will the third-party device administrator be able to grant access to authorized Google personnel upon request?", 16 | "answer": "N/A" 17 | }, 18 | { 19 | "question": "Which of the following statements are true about this device?", 20 | "answer": [0] 21 | }, 22 | { 23 | "question": "Does the network protocol assure server-to-client identity verification?", 24 | "answer": "Yes" 25 | }, 26 | { 27 | "question": "Click the statements that best describe the characteristics of this device.", 28 | "answer": [0] 29 | }, 30 | { 31 | "question": "Are any of the following statements true about this device?", 32 | "answer": [0] 33 | }, 34 | { 35 | "question": "Comments", 36 | "answer": "" 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /testing/api/sys_config/system.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "device_intf": "endev0a", 4 | "internet_intf": "dummynet" 5 | }, 6 | "log_level": "DEBUG" 7 | } -------------------------------------------------------------------------------- /testing/api/sys_config/updated_system.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "device_intf": "updated_endev0a", 4 | "internet_intf": "updated_dummynet" 5 | }, 6 | "log_level": "DEBUG" 7 | } -------------------------------------------------------------------------------- /testing/baseline/system.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "device_intf": "endev0a", 4 | "internet_intf": "eth0" 5 | }, 6 | "log_level": "DEBUG" 7 | } -------------------------------------------------------------------------------- /testing/device_configs/only_baseline/device_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "manufacturer": "Google", 3 | "model": "Baseline", 4 | "mac_addr": "02:42:aa:00:01:01", 5 | "test_modules": { 6 | "dns": { 7 | "enabled": false 8 | }, 9 | "connection": { 10 | "enabled": false 11 | }, 12 | "ntp": { 13 | "enabled": false 14 | }, 15 | "baseline": { 16 | "enabled": true 17 | }, 18 | "nmap": { 19 | "enabled": false 20 | }, 21 | "tls": { 22 | "enabled": false 23 | }, 24 | "protocol": { 25 | "enabled": false 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /testing/docker/ci_baseline/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM ubuntu@sha256:77d57fd89366f7d16615794a5b53e124d742404e20f035c22032233f1826bd6a 16 | 17 | # Update and get all additional requirements not contained in the base image 18 | RUN apt-get update && apt-get -y upgrade 19 | 20 | RUN apt-get install -y isc-dhcp-client ntpdate coreutils moreutils inetutils-ping curl jq dnsutils 21 | 22 | COPY entrypoint.sh /entrypoint.sh 23 | 24 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Update and get all additional requirements not contained in the base image 7 | RUN apt-get update && apt-get -y upgrade 8 | 9 | RUN apt-get update && apt-get install -y isc-dhcp-client ntpdate coreutils moreutils inetutils-ping curl jq dnsutils openssl netcat-openbsd arping 10 | 11 | COPY entrypoint.sh /entrypoint.sh 12 | 13 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/bacnet_compliant/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use Ubuntu base image 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | # Set non-interactive mode for apt 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | # Install dependencies 8 | RUN apt-get update && \ 9 | apt-get install -y isc-dhcp-client dnsutils netcat-openbsd arping python3 python3-pip && \ 10 | apt-get clean && rm -rf /var/lib/apt/lists/* 11 | 12 | # Install dependencies (BAC0) 13 | RUN pip install BAC0==23.7.3 pytz==2024.2 netifaces==0.11.0 14 | 15 | # Copy scripts 16 | WORKDIR /app 17 | COPY entrypoint.sh /entrypoint.sh 18 | COPY entrypoint.py /entrypoint.py 19 | 20 | # Make script executable 21 | RUN chmod +x /entrypoint.sh /entrypoint.py 22 | 23 | # Start BACnet device 24 | ENTRYPOINT ["/entrypoint.sh"] 25 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/bacnet_compliant/entrypoint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | BACnet/IP Virtual Device that Starts Without an IP (Waits for DHCP Assignment) 6 | """ 7 | 8 | import time 9 | import BAC0 10 | 11 | 12 | def start_bacnet_device(): 13 | """Starts the BACnet/IP virtual device with no pre-assigned IP.""" 14 | 15 | print("Starting BACnet Virtual Device...") 16 | 17 | bacnet = BAC0.lite(deviceId=999) 18 | 19 | bacnet.iam() 20 | 21 | while True: 22 | time.sleep(10) 23 | 24 | 25 | if __name__ == "__main__": 26 | start_bacnet_device() 27 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/bacnet_compliant/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | # Display network interfaces 4 | ip a 5 | 6 | INTF=eth0 7 | 8 | # DHCP 9 | ip addr flush dev $INTF 10 | PID_FILE=/var/run/dhclient.pid 11 | if [ -f $PID_FILE ]; then 12 | kill -9 $(cat $PID_FILE) || true 13 | rm -f $PID_FILE 14 | fi 15 | dhclient -v $INTF 16 | DHCP_TPID=$! 17 | echo $DHCP_TPID 18 | 19 | # Start BACnet device 20 | exec python3 /entrypoint.py 21 | 22 | # Keep network monitoring (can refactor later for other network modules) 23 | (while true; do arping 10.10.10.1; sleep 10; done) & 24 | (while true; do ip a | cat; sleep 10; done) & 25 | 26 | # Keep the script running 27 | tail -f /dev/null 28 | 29 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/dns_compliant/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Update the package list and upgrade the installed packages to their latest versions 7 | RUN apt-get update && apt-get -y upgrade 8 | 9 | # Install the necessary packages 10 | RUN apt-get update && apt-get install -y isc-dhcp-client dnsutils netcat-openbsd arping 11 | 12 | # Clean up the package lists to reduce the image size 13 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* 14 | 15 | COPY entrypoint.sh /entrypoint.sh 16 | 17 | RUN chmod +x /entrypoint.sh 18 | 19 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/dns_compliant/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | # Display network interfaces 4 | ip a 5 | 6 | # Set paths and servers 7 | DNS_SERVER=8.8.8.8 8 | INTF=eth0 9 | 10 | # DHCP 11 | ip addr flush dev $INTF 12 | PID_FILE=/var/run/dhclient.pid 13 | if [ -f $PID_FILE ]; then 14 | kill -9 $(cat $PID_FILE) || true 15 | rm -f $PID_FILE 16 | fi 17 | dhclient -v $INTF 18 | DHCP_TPID=$! 19 | echo $DHCP_TPID 20 | 21 | # DNS MODULE 22 | 23 | # Test DNS resolution 24 | echo "Sending DNS request to $DNS_SERVER" 25 | dig @$DNS_SERVER +short www.google.com 26 | 27 | # Keep network monitoring (can refactor later for other network modules) 28 | (while true; do arping 10.10.10.1; sleep 10; done) & 29 | (while true; do ip a | cat; sleep 10; done) & 30 | 31 | # Keep the script running 32 | tail -f /dev/null 33 | 34 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/dns_non_compliant/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Update the package list and upgrade the installed packages to their latest versions 7 | RUN apt-get update && apt-get -y upgrade 8 | 9 | # Install the necessary packages 10 | RUN apt-get update && apt-get install -y isc-dhcp-client ntp coreutils dnsutils netcat-openbsd arping 11 | 12 | # Clean up the package lists to reduce the image size 13 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* 14 | 15 | COPY entrypoint.sh /entrypoint.sh 16 | 17 | RUN chmod +x /entrypoint.sh 18 | 19 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/dns_non_compliant/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | # Display network interfaces 4 | ip a 5 | 6 | # Set paths and servers 7 | DNS_SERVER="nonexistent.dns.server" 8 | INTF=eth0 9 | 10 | # Check if the interface is up 11 | ip link show $INTF | grep "state UP" || echo "Warning: $INTF is not up" 12 | 13 | # DHCP setup 14 | ip addr flush dev $INTF 15 | PID_FILE=/var/run/dhclient.pid 16 | if [ -f $PID_FILE ]; then 17 | kill -9 $(cat $PID_FILE) || true 18 | rm -f $PID_FILE 19 | fi 20 | dhclient -v $INTF 21 | DHCP_TPID=$! 22 | echo $DHCP_TPID 23 | 24 | # DNS MODULE 25 | 26 | # Test DNS resolution 27 | echo "Sending DNS request to $DNS_SERVER" 28 | dig @$DNS_SERVER +short www.google.com || echo "DNS resolution failed" 29 | 30 | # Keep network monitoring 31 | (while true; do arping 10.10.10.1; sleep 10; done) & 32 | (while true; do ip a | cat; sleep 10; done) & 33 | 34 | # Keep the script running 35 | tail -f /dev/null 36 | 37 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/ntp_compliant/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Update the package list and upgrade the installed packages to their latest versions 7 | RUN apt-get update && apt-get -y upgrade 8 | 9 | # Install the necessary packages 10 | RUN apt-get update && apt-get install -y isc-dhcp-client netcat-openbsd arping ntpdate 11 | 12 | # Clean up the package lists to reduce the image size 13 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* 14 | 15 | COPY entrypoint.sh /entrypoint.sh 16 | 17 | RUN chmod +x /entrypoint.sh 18 | 19 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/ntp_non_compliant/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Update the package list and upgrade the installed packages to their latest versions 7 | RUN apt-get update && apt-get -y upgrade 8 | 9 | # Install the necessary packages 10 | RUN apt-get update && apt-get install -y isc-dhcp-client netcat-openbsd arping 11 | 12 | # Clean up the package lists to reduce the image size 13 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* 14 | 15 | COPY entrypoint.sh /entrypoint.sh 16 | 17 | RUN chmod +x /entrypoint.sh 18 | 19 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/ntp_non_compliant/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | # Display network interfaces 4 | ip a 5 | 6 | # Set paths and servers 7 | NTP_SERVER=10.10.10.5 8 | INTF=eth0 9 | 10 | # DHCP 11 | ip addr flush dev $INTF 12 | PID_FILE=/var/run/dhclient.pid 13 | if [ -f $PID_FILE ]; then 14 | kill -9 $(cat $PID_FILE) || true 15 | rm -f $PID_FILE 16 | fi 17 | dhclient -v $INTF 18 | DHCP_TPID=$! 19 | echo $DHCP_TPID 20 | 21 | # Keep network monitoring (can refactor later for other network modules) 22 | (while true; do arping 10.10.10.1; sleep 10; done) & 23 | (while true; do ip a | cat; sleep 10; done) & 24 | 25 | # Keep the script running 26 | tail -f /dev/null 27 | 28 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/protocol_compliant/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use Ubuntu base image 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | # Set non-interactive mode for apt 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | # Install dependencies 8 | RUN apt-get update && \ 9 | apt-get install -y isc-dhcp-client dnsutils netcat-openbsd arping python3 python3-pip && \ 10 | apt-get clean && rm -rf /var/lib/apt/lists/* 11 | 12 | # Install dependencies (BAC0) 13 | RUN pip install BAC0==23.7.3 pytz==2024.2 netifaces==0.11.0 pymodbus==3.0.0 pyserial pyserial-asyncio 14 | 15 | # Copy scripts 16 | WORKDIR /app 17 | COPY entrypoint.sh /entrypoint.sh 18 | COPY entrypoint.py /entrypoint.py 19 | 20 | # Make script executable 21 | RUN chmod +x /entrypoint.sh /entrypoint.py 22 | 23 | # Start BACnet device 24 | ENTRYPOINT ["/entrypoint.sh"] 25 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/protocol_compliant/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | # Display network interfaces 4 | ip a 5 | 6 | INTF=eth0 7 | 8 | # DHCP 9 | ip addr flush dev $INTF 10 | PID_FILE=/var/run/dhclient.pid 11 | if [ -f $PID_FILE ]; then 12 | kill -9 $(cat $PID_FILE) || true 13 | rm -f $PID_FILE 14 | fi 15 | dhclient -v $INTF 16 | DHCP_TPID=$! 17 | echo $DHCP_TPID 18 | 19 | # Start BACnet device 20 | exec python3 /entrypoint.py 21 | 22 | # Keep network monitoring (can refactor later for other network modules) 23 | (while true; do arping 10.10.10.1; sleep 10; done) & 24 | (while true; do ip a | cat; sleep 10; done) & 25 | 26 | # Keep the script running 27 | tail -f /dev/null 28 | 29 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/services_compliant/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Update the package list and upgrade the installed packages to their latest versions 7 | RUN apt-get update && apt-get -y upgrade 8 | 9 | # Install the necessary packages 10 | RUN apt-get update && apt-get install -y isc-dhcp-client dnsutils netcat-openbsd arping 11 | 12 | # Clean up the package lists to reduce the image size 13 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* 14 | 15 | COPY entrypoint.sh /entrypoint.sh 16 | 17 | RUN chmod +x /entrypoint.sh 18 | 19 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/services_compliant/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | # Display network interfaces 4 | ip a 5 | 6 | # Set path 7 | INTF=eth0 8 | 9 | # DHCP 10 | ip addr flush dev $INTF 11 | PID_FILE=/var/run/dhclient.pid 12 | if [ -f $PID_FILE ]; then 13 | kill -9 $(cat $PID_FILE) || true 14 | rm -f $PID_FILE 15 | fi 16 | dhclient -v $INTF 17 | DHCP_TPID=$! 18 | echo $DHCP_TPID 19 | 20 | # SERVICES MODULE 21 | 22 | # No FTP, SSH, Telnet, SMTP, HTTP, POP, IMAP services 23 | echo "FTP, SSH, Telnet, SMTP, HTTP, POP, IMAP, SNMP, VNC, TFTP, NTP services not running" 24 | 25 | # Keep network monitoring (can refactor later for other network modules) 26 | (while true; do arping 10.10.10.1; sleep 10; done) & 27 | (while true; do ip a | cat; sleep 10; done) & 28 | 29 | # Keep the script running 30 | tail -f /dev/null 31 | 32 | -------------------------------------------------------------------------------- /testing/docker/ci_test_device1/services_non_compliant/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM ubuntu@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # Update the package list and upgrade the installed packages to their latest versions 7 | RUN apt-get update && apt-get -y upgrade 8 | 9 | # Install the necessary packages 10 | RUN apt-get update && apt-get install -y isc-dhcp-client ntp coreutils dnsutils netcat-openbsd arping 11 | 12 | # Clean up the package lists to reduce the image size 13 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* 14 | 15 | COPY entrypoint.sh /entrypoint.sh 16 | 17 | RUN chmod +x /entrypoint.sh 18 | 19 | ENTRYPOINT ["/entrypoint.sh"] -------------------------------------------------------------------------------- /testing/example/mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/example/mac -------------------------------------------------------------------------------- /testing/tests/example/mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/tests/example/mac -------------------------------------------------------------------------------- /testing/tests/system.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "device_intf": "endev0a", 4 | "internet_intf": "eth0" 5 | }, 6 | "log_level": "DEBUG", 7 | "monitor_period": 30 8 | } -------------------------------------------------------------------------------- /testing/unit/conn/captures/monitor.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/conn/captures/monitor.pcap -------------------------------------------------------------------------------- /testing/unit/conn/captures/startup.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/conn/captures/startup.pcap -------------------------------------------------------------------------------- /testing/unit/conn/ethtool/ethtool_port_stats_post_monitor.txt: -------------------------------------------------------------------------------- 1 | NIC statistics: 2 | tx_packets: 124 3 | rx_packets: 216 4 | tx_errors: 0 5 | rx_errors: 0 6 | rx_missed: 0 7 | align_errors: 0 8 | tx_single_collisions: 0 9 | tx_multi_collisions: 0 10 | rx_unicast: 23 11 | rx_broadcast: 83 12 | rx_multicast: 110 13 | tx_aborted: 0 14 | tx_underrun: 0 -------------------------------------------------------------------------------- /testing/unit/conn/ethtool/ethtool_port_stats_post_monitor_noncompliant.txt: -------------------------------------------------------------------------------- 1 | NIC statistics: 2 | tx_packets: 124 3 | rx_packets: 216 4 | tx_errors: 5 5 | rx_errors: 12 6 | rx_missed: 0 7 | align_errors: 0 8 | tx_single_collisions: 0 9 | tx_multi_collisions: 0 10 | rx_unicast: 23 11 | rx_broadcast: 83 12 | rx_multicast: 110 13 | tx_aborted: 0 14 | tx_underrun: 0 -------------------------------------------------------------------------------- /testing/unit/conn/ethtool/ethtool_port_stats_pre_monitor.txt: -------------------------------------------------------------------------------- 1 | NIC statistics: 2 | tx_packets: 90 3 | rx_packets: 195 4 | tx_errors: 0 5 | rx_errors: 0 6 | rx_missed: 0 7 | align_errors: 0 8 | tx_single_collisions: 0 9 | tx_multi_collisions: 0 10 | rx_unicast: 12 11 | rx_broadcast: 78 12 | rx_multicast: 105 13 | tx_aborted: 0 14 | tx_underrun: 0 -------------------------------------------------------------------------------- /testing/unit/conn/ethtool/ethtool_results_compliant.txt: -------------------------------------------------------------------------------- 1 | Settings for enx123456789: 2 | Supported ports: [ TP MII ] 3 | Supported link modes: 10baseT/Half 10baseT/Full 4 | 100baseT/Half 100baseT/Full 5 | 1000baseT/Half 1000baseT/Full 6 | Supported pause frame use: No 7 | Supports auto-negotiation: Yes 8 | Supported FEC modes: Not reported 9 | Advertised link modes: 10baseT/Half 10baseT/Full 10 | 100baseT/Half 100baseT/Full 11 | 1000baseT/Full 12 | Advertised pause frame use: Symmetric Receive-only 13 | Advertised auto-negotiation: Yes 14 | Advertised FEC modes: Not reported 15 | Link partner advertised link modes: 10baseT/Full 16 | 100baseT/Half 100baseT/Full 17 | Link partner advertised pause frame use: Symmetric 18 | Link partner advertised auto-negotiation: Yes 19 | Link partner advertised FEC modes: Not reported 20 | Speed: 100Mb/s 21 | Duplex: Full 22 | Port: MII 23 | PHYAD: 32 24 | Transceiver: internal 25 | Auto-negotiation: on 26 | Supports Wake-on: pumbg 27 | Wake-on: g 28 | Current message level: 0x00007fff (32767) 29 | drv probe link timer ifdown ifup rx_err tx_err tx_queued intr tx_done rx_status pktdata hw wol 30 | Link detected: yes -------------------------------------------------------------------------------- /testing/unit/conn/ethtool/ethtool_results_no_autononegotiation.txt: -------------------------------------------------------------------------------- 1 | Settings for enx123456789: 2 | Supported ports: [ TP MII ] 3 | Supported link modes: 10baseT/Half 10baseT/Full 4 | 100baseT/Half 100baseT/Full 5 | 1000baseT/Half 1000baseT/Full 6 | Supported pause frame use: No 7 | Supports auto-negotiation: Yes 8 | Supported FEC modes: Not reported 9 | Advertised link modes: 10baseT/Half 10baseT/Full 10 | 100baseT/Half 100baseT/Full 11 | 1000baseT/Full 12 | Advertised pause frame use: Symmetric Receive-only 13 | Advertised auto-negotiation: Yes 14 | Advertised FEC modes: Not reported 15 | Link partner advertised link modes: 10baseT/Full 16 | 100baseT/Half 100baseT/Full 17 | Link partner advertised pause frame use: Symmetric 18 | Link partner advertised auto-negotiation: Yes 19 | Link partner advertised FEC modes: Not reported 20 | Speed: 100Mb/s 21 | Duplex: Full 22 | Port: MII 23 | PHYAD: 32 24 | Transceiver: internal 25 | Auto-negotiation: off 26 | Supports Wake-on: pumbg 27 | Wake-on: g 28 | Current message level: 0x00007fff (32767) 29 | drv probe link timer ifdown ifup rx_err tx_err tx_queued intr tx_done rx_status pktdata hw wol 30 | Link detected: yes -------------------------------------------------------------------------------- /testing/unit/conn/ethtool/ethtool_results_noncompliant.txt: -------------------------------------------------------------------------------- 1 | Settings for enx123456789: 2 | Supported ports: [ TP MII ] 3 | Supported link modes: 10baseT/Half 10baseT/Full 4 | 100baseT/Half 100baseT/Full 5 | 1000baseT/Half 1000baseT/Full 6 | Supported pause frame use: No 7 | Supports auto-negotiation: Yes 8 | Supported FEC modes: Not reported 9 | Advertised link modes: 10baseT/Half 10baseT/Full 10 | 100baseT/Half 100baseT/Full 11 | 1000baseT/Full 12 | Advertised pause frame use: Symmetric Receive-only 13 | Advertised auto-negotiation: Yes 14 | Advertised FEC modes: Not reported 15 | Link partner advertised link modes: 10baseT/Full 16 | 100baseT/Half 100baseT/Full 17 | Link partner advertised pause frame use: Symmetric 18 | Link partner advertised auto-negotiation: Yes 19 | Link partner advertised FEC modes: Not reported 20 | Speed: 10Mb/s 21 | Duplex: Half 22 | Port: MII 23 | PHYAD: 32 24 | Transceiver: internal 25 | Auto-negotiation: on 26 | Supports Wake-on: pumbg 27 | Wake-on: g 28 | Current message level: 0x00007fff (32767) 29 | drv probe link timer ifdown ifup rx_err tx_err tx_queued intr tx_done rx_status pktdata hw wol 30 | Link detected: yes -------------------------------------------------------------------------------- /testing/unit/conn/ifconfig/ifconfig_port_stats_post_monitor.txt: -------------------------------------------------------------------------------- 1 | enx00e04c6601a4: flags=4163 mtu 1500 2 | inet 192.168.228.1 netmask 255.255.255.0 broadcast 192.168.228.255 3 | inet6 fe80::2e0:4cff:fe66:1a4 prefixlen 64 scopeid 0x20 4 | ether 00:e0:4c:66:01:a4 txqueuelen 1000 (Ethernet) 5 | RX packets 23 bytes 2718 (2.7 KB) 6 | RX errors 0 dropped 0 overruns 0 frame 0 7 | TX packets 36 bytes 3831 (3.8 KB) 8 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 -------------------------------------------------------------------------------- /testing/unit/conn/ifconfig/ifconfig_port_stats_post_noncompliant_monitor.txt: -------------------------------------------------------------------------------- 1 | enx00e04c6601a4: flags=4163 mtu 1500 2 | inet 192.168.228.1 netmask 255.255.255.0 broadcast 192.168.228.255 3 | inet6 fe80::2e0:4cff:fe66:1a4 prefixlen 64 scopeid 0x20 4 | ether 00:e0:4c:66:01:a4 txqueuelen 1000 (Ethernet) 5 | RX packets 23 bytes 2718 (2.7 KB) 6 | RX errors 5 dropped 0 overruns 0 frame 7 7 | TX packets 36 bytes 3831 (3.8 KB) 8 | TX errors 10 dropped 0 overruns 0 carrier 0 collisions 0 -------------------------------------------------------------------------------- /testing/unit/conn/ifconfig/ifconfig_port_stats_pre_monitor.txt: -------------------------------------------------------------------------------- 1 | enx00e04c6601a4: flags=4163 mtu 1500 2 | inet 192.168.228.1 netmask 255.255.255.0 broadcast 192.168.228.255 3 | inet6 fe80::2e0:4cff:fe66:1a4 prefixlen 64 scopeid 0x20 4 | ether 00:e0:4c:66:01:a4 txqueuelen 1000 (Ethernet) 5 | RX packets 1 bytes 46 (46.0 B) 6 | RX errors 0 dropped 0 overruns 0 frame 0 7 | TX packets 2 bytes 180 (180.0 B) 8 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_dhcp_server/dns.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_dhcp_server/dns.pcap -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_dhcp_server/monitor.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_dhcp_server/monitor.pcap -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_dhcp_server/startup.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_dhcp_server/startup.pcap -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_no_dns/dns.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_no_dns/dns.pcap -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_no_dns/monitor.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_no_dns/monitor.pcap -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_no_dns/startup.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_no_dns/startup.pcap -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_non_dhcp_server/dns.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_non_dhcp_server/dns.pcap -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_non_dhcp_server/monitor.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_non_dhcp_server/monitor.pcap -------------------------------------------------------------------------------- /testing/unit/dns/captures/dns_non_dhcp_server/startup.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/dns/captures/dns_non_dhcp_server/startup.pcap -------------------------------------------------------------------------------- /testing/unit/ntp/captures/monitor.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/ntp/captures/monitor.pcap -------------------------------------------------------------------------------- /testing/unit/ntp/captures/ntp.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/ntp/captures/ntp.pcap -------------------------------------------------------------------------------- /testing/unit/ntp/captures/startup.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/ntp/captures/startup.pcap -------------------------------------------------------------------------------- /testing/unit/protocol/captures/bacnet.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/protocol/captures/bacnet.pcap -------------------------------------------------------------------------------- /testing/unit/services/output/services_report.html: -------------------------------------------------------------------------------- 1 |

Services Module

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
TCP ports openUDP ports openTotal ports open
000
17 | 18 |
19 |
20 | No open ports detected 21 |
-------------------------------------------------------------------------------- /testing/unit/tls/CertAuth/Testrun_CA_Root.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICyjCCAbICAQAwgYQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh 3 | MRUwEwYDVQQHDAxNb3VudGFpblZpZXcxEDAOBgNVBAoMB1Rlc3RydW4xFjAUBgNV 4 | BAsMDVF1YWxpZmljYXRpb24xHzAdBgNVBAMMFlRlc3RydW4gUlNBIFNpZ25pbmcg 5 | Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDABwO+XX0q6E1iysiS 6 | JBxo+XILBxg20HMTdMGc4Kdyt5gm1mfkXIBL1XNGRPENLoV/Ty0K2EnmexVLllU8 7 | 27hf5kb29YRSzWb5wQd1tpexZ2Bnj3FTb/Xmacej8Oo4WF/PxKZ1mkYDmQp77h61 8 | zJpbooWaX3AdjYpmrKiQxjV6EAxykYzVLXqueYecra3IAzbuujvHQJwxKrQbbhJa 9 | UQrtYY5CKd3BjqAU0PXqulHjfGPxOau+QA+zkGsAu/DZuRdxk7VON7H3CR7ywZV6 10 | 3ul8/3VUDlQYPSkOq2hBo50KzINXJ4BFl0V7q03Ru3dPRxssqp52Qzg8BggFuKdx 11 | pucDAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAZBPnCRmf8mmQr26XJWOri/EU 12 | B+PXPQ1CZInULKAC2g+Eyz279Bx/73kQ/+G++4p2XTiHzLH6V3d0sQzTmNKm7fz9 13 | jGuHSLkRYlo983dlTmnJTKdE+Z9heMbzIYuusbgt8SshHQejUxLpZ7muB+Kcg5wE 14 | andVgm4RY8sz9/Hwk1GRaMFjEeeOcN3S6ZAs086BWfsG/2rJbntPabA9GDNvdfqJ 15 | pp8opOB7p0Uxfy3eYEYNWdEp4s2JwaEoAWDFI2gHeawIbJ/cldY5YOg7AHY9nl8I 16 | XcdcV1mreAlrrZhODqg0EatUokgAyR1KDPIt4q6ME5nqjEjLaE3+dy7kGgbYWg== 17 | -----END CERTIFICATE REQUEST----- 18 | -------------------------------------------------------------------------------- /testing/unit/tls/CertAuth/Testrun_CA_Root.srl: -------------------------------------------------------------------------------- 1 | 31B6EB0B91479F0EC0DFC4D82787EB2736DF6908 2 | -------------------------------------------------------------------------------- /testing/unit/tls/CertAuth/device_cert_local.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDizCCAnMCFDG26wuRR58OwN/E2CeH6yc232kIMA0GCSqGSIb3DQEBCwUAMIGE 3 | MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UEBwwMTW91 4 | bnRhaW5WaWV3MRAwDgYDVQQKDAdUZXN0cnVuMRYwFAYDVQQLDA1RdWFsaWZpY2F0 5 | aW9uMR8wHQYDVQQDDBZUZXN0cnVuIFJTQSBTaWduaW5nIENBMB4XDTI0MDMyMDIw 6 | MzYxMFoXDTI5MDMyMDIwMzYxMFowfzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh 7 | bGlmb3JuaWExFTATBgNVBAcMDE1vdW50YWluVmlldzEQMA4GA1UECgwHVGVzdHJ1 8 | bjEWMBQGA1UECwwNUXVhbGlmaWNhdGlvbjEaMBgGA1UEAwwRZGV2aWNlX2NlcnRf 9 | bG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJepNW0Aag19mp 10 | a0DwbTupjsQPuQPxhXQ+0fEHNHycuPxW7MDlpeTfVC1tPlBu/X6uK3yCYco1YDEv 11 | tTXYBELjnHUynnCh/ZKcoGMBO+wo3q/ppU2PC8E9wKwH0R070OzKj0U2LR2wHiLN 12 | x4HpUAbrP/aH7qS9tNswqL/oE+dsPzpa2JY3a8dpUHa/x7iVmasasLrteht3Iz84 13 | 9QLki9O1vUGA5jTKx9CAymIZGFf19gJ3qiqIPNvY6a6cv5ACykTYOTn/X3LOK8Zu 14 | Vv7/8M5z8Uf/t4bVK5wyIo+KBG7L1tpYjuGLrAOqOauNgsrUD2DQbsNds4Evjpt9 15 | dItalZtjAgMBAAEwDQYJKoZIhvcNAQELBQADggEBALkVmv0pwISSckgbCJ9Y16iu 16 | I/qzNUmrBX/O36pXFDYj++YDWQyAXxrFK2mb8+wE5VjtnW+XIYQ5HMD65xaajqjC 17 | 14Rq9n7nSH1WvXBRVyOZLO/iXabofqpNZq/8t8I6Gwr7nDLui8g41Aa6UCzqO+vu 18 | ud07PUDj3TwFcE3YBU9oT9Cxbu9dgFWEu53hO2+Wef9V5MYAOvsiaakUy4sxyEvn 19 | SrRpTR5x25TahIM9AfuDIBAeQGsw0q0Pl10JY4n+Z+rFvc6yvuzsmZCzqZiQGiC7 20 | jkgjxxuR2aKopXoC1sKZ5NhueNkXQjnYwebQp+gkoDamoEIUHMVjCm1bvOu9M/Q= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /testing/unit/tls/CertAuth/device_cert_local.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICxDCCAawCAQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx 3 | FTATBgNVBAcMDE1vdW50YWluVmlldzEQMA4GA1UECgwHVGVzdHJ1bjEWMBQGA1UE 4 | CwwNUXVhbGlmaWNhdGlvbjEaMBgGA1UEAwwRZGV2aWNlX2NlcnRfbG9jYWwwggEi 5 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJepNW0Aag19mpa0DwbTupjsQP 6 | uQPxhXQ+0fEHNHycuPxW7MDlpeTfVC1tPlBu/X6uK3yCYco1YDEvtTXYBELjnHUy 7 | nnCh/ZKcoGMBO+wo3q/ppU2PC8E9wKwH0R070OzKj0U2LR2wHiLNx4HpUAbrP/aH 8 | 7qS9tNswqL/oE+dsPzpa2JY3a8dpUHa/x7iVmasasLrteht3Iz849QLki9O1vUGA 9 | 5jTKx9CAymIZGFf19gJ3qiqIPNvY6a6cv5ACykTYOTn/X3LOK8ZuVv7/8M5z8Uf/ 10 | t4bVK5wyIo+KBG7L1tpYjuGLrAOqOauNgsrUD2DQbsNds4Evjpt9dItalZtjAgMB 11 | AAGgADANBgkqhkiG9w0BAQsFAAOCAQEAilL337tVPh+cZl2jY5FCeNRBJ8thfgfZ 12 | 95qcQsV0QmZgeDVmYRPl2N23v+lyM0KPDyRVG4MJCMH4SanBWftAjnTe17rroXO4 13 | /+tfDPpseH5FrwdbrYM6pixqWxhVttWGFkPCg9Yl/wKtSh6+IMN9I5CVFjmIPIVS 14 | 0NviJ/H4yuv0gSZ2mXs+fWAC7TpbBlVSU8L4DzdyMJZ+w1xxK8Q4vQ40wQYPjZG5 15 | 5Dfm5MDG+vhO8+9wYW5kUH/bPd4F47j80Sivc6DxxDgtITRbxlV1dwFwagpYRNcx 16 | yOKJyUiL4YH3IRT6VCFJ28TNab3QHFrJyS/MlnEJJOuCBY9GAl6GBg== 17 | -----END CERTIFICATE REQUEST----- 18 | -------------------------------------------------------------------------------- /testing/unit/tls/CertAuth/generateCA.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Generate new unencrypted private key 4 | openssl genrsa -out Testrun_CA_Root.key 2048 5 | 6 | #Generate a new csr. 7 | openssl req -new -key Testrun_CA_Root.key -out Testrun_CA_Root.csr -subj "/C=US/ST=California/L=MountainView/O=Testrun/OU=Qualification/CN=Testrun RSA Signing CA" 8 | 9 | #Generate and self sign the CA cert 10 | openssl x509 -req -days 3652 -in Testrun_CA_Root.csr -signkey Testrun_CA_Root.key -sha256 -out Testrun_CA_Root.crt 11 | 12 | #Copy the generated cirt to the local root_certs directory 13 | cp Testrun_CA_Root.crt ../root_certs -------------------------------------------------------------------------------- /testing/unit/tls/CertAuth/generateLocalCert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Helper script to generate the local certificate 4 | # used for unit testing. This script should be run 5 | # directly from the directory where it lives for 6 | # proper CA certificate resolving during signing process 7 | 8 | CA_ROOT_CERT_NAME="Testrun_CA_Root" 9 | CA_ROOT_DIR="." 10 | CA_ROOT_KEY=$CA_ROOT_DIR/$CA_ROOT_CERT_NAME.key 11 | CA_ROOT_CERT=$CA_ROOT_DIR/$CA_ROOT_CERT_NAME.crt 12 | 13 | 14 | CERT_NAME="device_cert_local" 15 | 16 | #Generate the private key 17 | openssl genrsa -out $CERT_NAME.key 2048 18 | 19 | #Generate the CSR 20 | openssl req -new -key $CERT_NAME.key -out $CERT_NAME.csr -subj "/C=US/ST=California/L=MountainView/O=Testrun/OU=Qualification/CN=$CERT_NAME" 21 | 22 | #Generate and sign the certificate with the local CA 23 | openssl x509 -req -days 1826 -in $CERT_NAME.csr -CA $CA_ROOT_CERT -CAkey $CA_ROOT_KEY -CAcreateserial -out $CERT_NAME.crt 24 | 25 | cp $CERT_NAME.crt ../certs -------------------------------------------------------------------------------- /testing/unit/tls/captures/monitor.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/monitor.pcap -------------------------------------------------------------------------------- /testing/unit/tls/captures/monitor_with_quic.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/monitor_with_quic.pcap -------------------------------------------------------------------------------- /testing/unit/tls/captures/multi_page_monitor.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/multi_page_monitor.pcap -------------------------------------------------------------------------------- /testing/unit/tls/captures/multi_page_startup.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/multi_page_startup.pcap -------------------------------------------------------------------------------- /testing/unit/tls/captures/multi_page_tls.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/multi_page_tls.pcap -------------------------------------------------------------------------------- /testing/unit/tls/captures/no_tls.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/no_tls.pcap -------------------------------------------------------------------------------- /testing/unit/tls/captures/tls.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/tls.pcap -------------------------------------------------------------------------------- /testing/unit/tls/captures/tls_ext.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/tls_ext.pcap -------------------------------------------------------------------------------- /testing/unit/tls/captures/unsupported_tls.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/captures/unsupported_tls.pcap -------------------------------------------------------------------------------- /testing/unit/tls/monitor.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/monitor.pcap -------------------------------------------------------------------------------- /testing/unit/tls/no_tls.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/no_tls.pcap -------------------------------------------------------------------------------- /testing/unit/tls/reports/tls_report_no_cert_local.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | {# Badge #} 6 |

7 | 8 | {{ name }} 9 |

10 | {{ title }} 11 |
12 | 13 | {{ device['manufacturer'] }} 14 | {{ device['model']}} 15 | 16 | Testrun 17 |
18 |
19 |

TLS Module

20 |
21 |
22 | No TLS certificates found on the device 23 |
24 |
25 | 26 | 30 |
31 |
32 | -------------------------------------------------------------------------------- /testing/unit/tls/unsupported_tls.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/testrun/1e65cb249d819eedb53c2dade7d8426a4d4b4d15/testing/unit/tls/unsupported_tls.pcap --------------------------------------------------------------------------------