forked from clan/clan-core
Compare commits
3 Commits
main
...
ui-testing
Author | SHA1 | Date | |
---|---|---|---|
246457ffa2 | |||
bd5fd8b7b1 | |||
54e9439f0a |
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
lib,
|
||||
stdenv,
|
||||
weston,
|
||||
python3,
|
||||
runCommand,
|
||||
setuptools,
|
||||
|
@ -14,8 +17,7 @@
|
|||
libadwaita,
|
||||
pytest, # Testing framework
|
||||
pytest-cov, # Generate coverage reports
|
||||
pytest-subprocess, # fake the real subprocess behavior to make your tests more independent.
|
||||
pytest-xdist, # Run tests in parallel on multiple cores
|
||||
pytest-subprocess, # fake the real subprocess behavior to make your tests more independent. # Run tests in parallel on multiple cores
|
||||
pytest-timeout, # Add timeouts to your tests
|
||||
}:
|
||||
let
|
||||
|
@ -52,9 +54,9 @@ let
|
|||
pytest # Testing framework
|
||||
pytest-cov # Generate coverage reports
|
||||
pytest-subprocess # fake the real subprocess behavior to make your tests more independent.
|
||||
pytest-xdist # Run tests in parallel on multiple cores
|
||||
pytest-timeout # Add timeouts to your tests
|
||||
];
|
||||
]
|
||||
++ (lib.optionals stdenv.isLinux [ weston ]);
|
||||
|
||||
# Dependencies required for running tests
|
||||
testDependencies = runtimeDependencies ++ allPythonDeps ++ externalTestDeps;
|
||||
|
|
|
@ -19,7 +19,7 @@ testpaths = "tests"
|
|||
faulthandler_timeout = 60
|
||||
log_level = "DEBUG"
|
||||
log_format = "%(levelname)s: %(message)s\n %(pathname)s:%(lineno)d::%(funcName)s"
|
||||
addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail --durations 5 --color=yes --new-first" # Add --pdb for debugging
|
||||
addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail --durations 5 --color=yes -vv --new-first" # Add --pdb for debugging
|
||||
norecursedirs = "tests/helpers"
|
||||
markers = ["impure"]
|
||||
|
||||
|
@ -29,11 +29,17 @@ warn_redundant_casts = true
|
|||
disallow_untyped_calls = true
|
||||
disallow_untyped_defs = true
|
||||
no_implicit_optional = true
|
||||
exclude = '^tests/helpers/libvncclient.py$'
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = "clan_cli.*"
|
||||
ignore_missing_imports = true
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = "libvncclient.*"
|
||||
ignore_missing_imports = true
|
||||
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
line-length = 88
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
python3,
|
||||
gtk4,
|
||||
libadwaita,
|
||||
tigervnc,
|
||||
libvncserver,
|
||||
}:
|
||||
|
||||
let
|
||||
|
@ -31,6 +33,9 @@ mkShell {
|
|||
ruff
|
||||
gtk4.dev # has the demo called 'gtk4-widget-factory'
|
||||
libadwaita.devdoc # has the demo called 'adwaita-1-demo'
|
||||
tigervnc
|
||||
libvncserver.dev
|
||||
libvncserver
|
||||
]
|
||||
++ devshellTestDeps
|
||||
|
||||
|
@ -40,14 +45,28 @@ mkShell {
|
|||
desktop-file-utils # verify desktop files
|
||||
]);
|
||||
|
||||
# Use ipdb as the default debugger for python
|
||||
PYTHONBREAKPOINT = "ipdb.set_trace";
|
||||
|
||||
hardeningDisabled = "all";
|
||||
|
||||
shellHook = ''
|
||||
export LIBVNC_INCLUDE=${libvncserver.dev}/include
|
||||
export LIBVNC_LIB=${libvncserver}/lib
|
||||
|
||||
export GIT_ROOT=$(git rev-parse --show-toplevel)
|
||||
export PKG_ROOT=$GIT_ROOT/pkgs/clan-vm-manager
|
||||
|
||||
# Add clan-vm-manager command to PATH
|
||||
export PATH="$PKG_ROOT/bin":"$PATH"
|
||||
export PATH="$GIT_ROOT/pkgs/clan-vm-manager/bin":"$PATH"
|
||||
|
||||
# Add clan-vm-manager to the python path so that we can
|
||||
# import it in the tests
|
||||
export PYTHONPATH="$GIT_ROOT/pkgs/clan-vm-manager":"$PYTHONPATH"
|
||||
|
||||
# Add clan-cli to the python path so that we can import it without building it in nix first
|
||||
export PYTHONPATH="$GIT_ROOT/pkgs/clan-cli":"$PYTHONPATH"
|
||||
|
||||
# Add clan-cli to the PATH
|
||||
export PATH="$GIT_ROOT/pkgs/clan-cli/bin":"$PATH"
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -7,9 +7,6 @@ from clan_cli.custom_logger import setup_logging
|
|||
from clan_cli.nix import nix_shell
|
||||
|
||||
sys.path.append(str(Path(__file__).parent / "helpers"))
|
||||
sys.path.append(
|
||||
str(Path(__file__).parent.parent)
|
||||
) # Also add clan vm manager to PYTHONPATH
|
||||
|
||||
pytest_plugins = [
|
||||
"temporary_dir",
|
||||
|
|
12
pkgs/clan-vm-manager/tests/data/vnc-security/ca.crl
Normal file
12
pkgs/clan-vm-manager/tests/data/vnc-security/ca.crl
Normal file
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN X509 CRL-----
|
||||
MIIB2zCBxAIBATANBgkqhkiG9w0BAQsFADCBgDELMAkGA1UEBhMCVVMxEjAQBgNV
|
||||
BAgMCVlvdXJTdGF0ZTERMA8GA1UEBwwIWW91ckNpdHkxGzAZBgNVBAoMEllvdXJD
|
||||
QU9yZ2FuaXphdGlvbjEZMBcGA1UECwwQWW91ckNBRGVwYXJ0bWVudDESMBAGA1UE
|
||||
AwwJMTI3LjAuMC4xFw0yNDA0MDExMzQ4MTBaFw0yNDA1MDExMzQ4MTBaoA8wDTAL
|
||||
BgNVHRQEBAICEAAwDQYJKoZIhvcNAQELBQADggEBAKlXZYq3euvI5jdDreK6o9YQ
|
||||
VtdLzdf/J0kQF8MVFjPo+x585xKYu2YgFLBmvZ5Jfpi6MjYH6E/liJdT1be16lDo
|
||||
/CYy+55UdUgm61rordF+ddWQBcr4+Nw9k9ZQIdOMtHbleLRwk/hLvJ3d/3A+emVb
|
||||
vs2I07tG+hfqkR2NlY5ff4cutd2WdVCcHYw0cF2S785cY+LfDz92bT03lswfm0qz
|
||||
PoJbKtk2FYRcpddC3KxQl4gSDzmyiWEMuzOHDflMJO0K5OPvuzTc9JChS0n+Qb2y
|
||||
klFtCZskKDy1NpM+pLH/RgFmivs8xiLAOsyk5/Ln5itHH1lm/pSaaj2XtI4aTSk=
|
||||
-----END X509 CRL-----
|
24
pkgs/clan-vm-manager/tests/data/vnc-security/ca.crt
Normal file
24
pkgs/clan-vm-manager/tests/data/vnc-security/ca.crt
Normal file
|
@ -0,0 +1,24 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIID9DCCAtygAwIBAgIURrbmCTlyih5uvTVoknewtlE0M6QwDQYJKoZIhvcNAQEL
|
||||
BQAwgYAxCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlZb3VyU3RhdGUxETAPBgNVBAcM
|
||||
CFlvdXJDaXR5MRswGQYDVQQKDBJZb3VyQ0FPcmdhbml6YXRpb24xGTAXBgNVBAsM
|
||||
EFlvdXJDQURlcGFydG1lbnQxEjAQBgNVBAMMCTEyNy4wLjAuMTAeFw0yNDAzMjgx
|
||||
MTUwMDFaFw0zNDAzMjYxMTUwMDFaMIGAMQswCQYDVQQGEwJVUzESMBAGA1UECAwJ
|
||||
WW91clN0YXRlMREwDwYDVQQHDAhZb3VyQ2l0eTEbMBkGA1UECgwSWW91ckNBT3Jn
|
||||
YW5pemF0aW9uMRkwFwYDVQQLDBBZb3VyQ0FEZXBhcnRtZW50MRIwEAYDVQQDDAkx
|
||||
MjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcb6ZpdEVi
|
||||
D/TAdMtpI/lLOLBnBuA5+5+SEbq2M3U+7tmZ1GxhuJhFddP+JbLq84X5BzFYS3Be
|
||||
Hn9W+iHOr58BvAdFi6lS1H7w5ZwRPXsZ+/HlydWBszKmTi7h8ByB5UnOezduRc26
|
||||
gT6zPLtMXuUCAN9dAmThCA2G74EwUTJyZYOql+8wM3BbfE6wcnVdkADQcqFs86C4
|
||||
0o9qitOoCXmtdd9TVDkyLcQMgxEx1W3LHvH2lNpp60T/FetilrdqsICaon/IbiYf
|
||||
XeUtqUE2L61Os8Y0FqRxquMIgYm+vPtTOQk8v4slNmsnl/veFY+SpNt3pY1FNK6b
|
||||
n1XaZop9p2pLAgMBAAGjZDBiMB0GA1UdDgQWBBReyxFuGLwIL/Q/dJXUSv51s4my
|
||||
6TAfBgNVHSMEGDAWgBReyxFuGLwIL/Q/dJXUSv51s4my6TAPBgNVHRMBAf8EBTAD
|
||||
AQH/MA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBAHC+9xYh9P5v
|
||||
wGr1HY+tQdDzc0xpsXGtsHbUK859OJXI8HWew6+iAefMrnKBYBXphnmp5IolHlP+
|
||||
qaUs2Y7Lih+z28skQh2kpJHnJMKbAN0MLucA6NTbRdQD7EyAO91cuZQ7PS3DyAvy
|
||||
DosjgK4aMvpd07cbYLCTqaczz4KN/EdjMcvK2QelqtzZphGq+5meQDafLXBtf+CG
|
||||
MmTh9szwYzzk7dGurNdsgugNNvk/X0p074SWjLvsK5FCuRJEh23Wx3bWBDMiVUcr
|
||||
RrgVjJ47Jyeozto4whOglQRk9hc2VBjmeXBYlmi+PorcRFZrvAdWilBCsi37ki2G
|
||||
qTrAwVx06AE=
|
||||
-----END CERTIFICATE-----
|
28
pkgs/clan-vm-manager/tests/data/vnc-security/ca.key
Normal file
28
pkgs/clan-vm-manager/tests/data/vnc-security/ca.key
Normal file
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcb6ZpdEViD/TA
|
||||
dMtpI/lLOLBnBuA5+5+SEbq2M3U+7tmZ1GxhuJhFddP+JbLq84X5BzFYS3BeHn9W
|
||||
+iHOr58BvAdFi6lS1H7w5ZwRPXsZ+/HlydWBszKmTi7h8ByB5UnOezduRc26gT6z
|
||||
PLtMXuUCAN9dAmThCA2G74EwUTJyZYOql+8wM3BbfE6wcnVdkADQcqFs86C40o9q
|
||||
itOoCXmtdd9TVDkyLcQMgxEx1W3LHvH2lNpp60T/FetilrdqsICaon/IbiYfXeUt
|
||||
qUE2L61Os8Y0FqRxquMIgYm+vPtTOQk8v4slNmsnl/veFY+SpNt3pY1FNK6bn1Xa
|
||||
Zop9p2pLAgMBAAECggEAOHy77iYHaZuhInhLb8PyLB54xc3zQ6iBOZMlf28sSlY2
|
||||
mL7gjyIYkyQgkO3kLWT+HdSEBpY+U0AJbaZnZ2mFm5ItYtrpJvqhFOYh2iEhHIV9
|
||||
dV8FQVlET22VgfxfscGp6imVCMMGdxaLlK6paGag1KSYmGL2qtu/a6aQOmt0O+/h
|
||||
iWYSpl2Rgdwi85fyEay/ziccmPKbkJEt4yjqhcEjzxZi+NDYvqEkdCa47pKZB6mY
|
||||
5E8Eh+HdMaBNx1tVcs5gclQBm4PjTLFPpZohbVZiv88hvP79RYlIGHvUiWkEN4A7
|
||||
6uGgJEcCH85SHNEE6Bfg9kD9nW2Lq4jvDJ0tMhibQQKBgQD+E13YmewzzROy8UKY
|
||||
FxN8gqHWSkRJ5v1vP/z7WSibGOpkhLwRL2p4HHPvpU6F1272E3cPSHEDZ7QbrBn1
|
||||
gWfCFk8zyj/LxEtvDsfEYL/ShKvDVXBaKmb8llILIR1LbtqEKu+hkuEDSmaFv9Gw
|
||||
nGcfj3B2RN4LlZmmRQE0Adf4UQKBgQDeGw8ZyA9yd1XYsdHoh+YxZVZv+mxxU1SO
|
||||
AYlmEBSFbrzl+zMg+exgb5GRmYWKSqhSvw0yGjcy37SAXDK4+faXyZ2YR2NjVzDh
|
||||
4Odqu4aYwE7HU5Y/9zpsn40qc9UylRDBkcX9Dekj1b9hRzj19nFNVBJGjgZRLgMV
|
||||
57UgGxPt2wKBgHMzLsLuD4XxPzRMZch19hTnWh/CbrIfdNvDZJ5Gb73bDzPiZy9X
|
||||
k2vAYuTOzAqtgpc6fipEy1Ei7Sv63Y5OTVBYMzMlScXHS/if9/3XbEI0e3jGvXl0
|
||||
bluqgKqhKhowug1hNmPJKBMI4fFU5uuwDqXlsLU/Rnp0K0WTVhdRmq3xAoGAQTpz
|
||||
KeAuYTCY3qYCfqcCvLkFNKe4F2Qgrf/XiUjprfJCucwXTPT5La02dCtBI8cfPgXr
|
||||
6y31zhQS36u0Hc0TVaqZhPJaRv+BVKUHcboXIl9AA5wRwUFrQCFvhOs1zsAmhqK4
|
||||
IcRnFuYcaYZQPTQePFaXc28cfdTkhRdig0ZQiQcCgYEAtUGFZHsKP+Ft23m4X9KR
|
||||
nYBehkG/L3S9PinXIBQU/32R1lc2G/ziMYijh8p9fYlzYm3AkkFURfBPHvCm8nl8
|
||||
xduLA2D/CPb1HelwcuPNSrK6bJbu/Knn73ki1DUDtOQI/MhUc83SudGYzkPJvZTU
|
||||
r5QeLVBf34I4meNOzOOXmag=
|
||||
-----END PRIVATE KEY-----
|
1
pkgs/clan-vm-manager/tests/data/vnc-security/ca.srl
Normal file
1
pkgs/clan-vm-manager/tests/data/vnc-security/ca.srl
Normal file
|
@ -0,0 +1 @@
|
|||
070517FB67B9D171836447F4C188BB6C1F52E712
|
1
pkgs/clan-vm-manager/tests/data/vnc-security/crlnumber
Normal file
1
pkgs/clan-vm-manager/tests/data/vnc-security/crlnumber
Normal file
|
@ -0,0 +1 @@
|
|||
1001
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Check if openssl is available
|
||||
if ! command -v openssl &> /dev/null; then
|
||||
echo "openssl is not installed. Please install openssl to generate the certificates."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 0: Define CA subject details
|
||||
CA_SUBJECT="/C=US/ST=YourState/L=YourCity/O=YourCAOrganization/OU=YourCADepartment/CN=127.0.0.1"
|
||||
|
||||
# Step 1: Generate the CA's private key
|
||||
openssl genpkey -algorithm RSA -out ca.key -pkeyopt rsa_keygen_bits:2048
|
||||
|
||||
# Step 2: Create a self-signed CA certificate
|
||||
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj "$CA_SUBJECT" -addext "subjectAltName = IP:127.0.0.1"
|
||||
|
||||
# Step 3: Generate a private key for the TLS certificate
|
||||
openssl genpkey -algorithm RSA -out tls.key -pkeyopt rsa_keygen_bits:2048
|
||||
|
||||
# Step 4: Create a Certificate Signing Request (CSR) for the TLS certificate
|
||||
TLS_SUBJECT="/C=US/ST=YourState/L=YourCity/O=YourOrganization/OU=YourDepartment/CN=127.0.0.1"
|
||||
openssl req -new -key tls.key -out tls.csr -subj "$TLS_SUBJECT" -addext "subjectAltName = IP:127.0.0.1"
|
||||
|
||||
# Step 5: Sign the CSR with your CA to generate the TLS certificate
|
||||
openssl x509 -req -in tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out tls.crt -days 365 -sha256 -extfile <(printf "subjectAltName=IP:127.0.0.1")
|
||||
|
||||
# Step 6: Generate a ca.crl file needed for libvncserver
|
||||
openssl ca -config ./openssl.conf -gencrl -keyfile ca.key -cert ca.crt -out ca.crl
|
||||
|
||||
echo "CA and TLS certificate, CSR, and key have been generated."
|
65
pkgs/clan-vm-manager/tests/data/vnc-security/openssl.conf
Normal file
65
pkgs/clan-vm-manager/tests/data/vnc-security/openssl.conf
Normal file
|
@ -0,0 +1,65 @@
|
|||
[ ca ]
|
||||
default_ca = CA_default
|
||||
|
||||
[ CA_default ]
|
||||
dir = . # Where everything is stored
|
||||
certs = $dir/certs # Where the issued certs are kept
|
||||
crl_dir = $dir/crl # Where the issued crl are kept
|
||||
database = $dir/index.txt # Database index file
|
||||
new_certs_dir = $dir/newcerts
|
||||
certificate = $dir/cacert.pem # The CA certificate
|
||||
serial = $dir/serial # The current serial number
|
||||
crlnumber = $dir/crlnumber # The current crl number
|
||||
crl = $dir/crl.pem # The current CRL
|
||||
private_key = $dir/private/cakey.pem
|
||||
RANDFILE = $dir/private/.rand
|
||||
|
||||
x509_extensions = usr_cert # The extensions to add to the cert
|
||||
crlnumber = $dir/crlnumber # the current crl number must be commented out to leave a V1 CRL
|
||||
crl = $dir/crl.pem # The current CRL
|
||||
private_key = $dir/private/cakey.pem
|
||||
RANDFILE = $dir/private/.rand
|
||||
|
||||
default_days = 365 # How long to certify for
|
||||
default_crl_days = 30 # How long before next CRL
|
||||
default_md = sha256 # Which md to use.
|
||||
preserve = no # Keep passed DN ordering
|
||||
|
||||
policy = policy_match
|
||||
|
||||
[ policy_match ]
|
||||
countryName = optional
|
||||
stateOrProvinceName = optional
|
||||
organizationName = optional
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
default_md = sha256
|
||||
prompt = no
|
||||
distinguished_name = req_distinguished_name
|
||||
x509_extensions = v3_ca
|
||||
|
||||
[ req_distinguished_name ]
|
||||
countryName = US
|
||||
stateOrProvinceName = California
|
||||
localityName = San Francisco
|
||||
0.organizationName = My Organization
|
||||
organizationalUnitName = My Organizational Unit
|
||||
commonName = My CA
|
||||
emailAddress = email@example.com
|
||||
|
||||
[ v3_ca ]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical,CA:true
|
||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
||||
|
||||
[ usr_cert ]
|
||||
basicConstraints = CA:FALSE
|
||||
nsComment = "OpenSSL Generated Certificate"
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid,issuer
|
||||
|
23
pkgs/clan-vm-manager/tests/data/vnc-security/tls.crt
Normal file
23
pkgs/clan-vm-manager/tests/data/vnc-security/tls.crt
Normal file
|
@ -0,0 +1,23 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIID3jCCAsagAwIBAgIUBwUX+2e50XGDZEf0wYi7bB9S5xIwDQYJKoZIhvcNAQEL
|
||||
BQAwgYAxCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlZb3VyU3RhdGUxETAPBgNVBAcM
|
||||
CFlvdXJDaXR5MRswGQYDVQQKDBJZb3VyQ0FPcmdhbml6YXRpb24xGTAXBgNVBAsM
|
||||
EFlvdXJDQURlcGFydG1lbnQxEjAQBgNVBAMMCTEyNy4wLjAuMTAeFw0yNDAzMjgx
|
||||
MTUwMDJaFw0yNTAzMjgxMTUwMDJaMHwxCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlZ
|
||||
b3VyU3RhdGUxETAPBgNVBAcMCFlvdXJDaXR5MRkwFwYDVQQKDBBZb3VyT3JnYW5p
|
||||
emF0aW9uMRcwFQYDVQQLDA5Zb3VyRGVwYXJ0bWVudDESMBAGA1UEAwwJMTI3LjAu
|
||||
MC4xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwYSlR4nEj4LuNclm
|
||||
QFfqei1FU+bvLggzWzNNGfhGiqArzV8F7snUGaGymA6ZbXAj//Z+XXDQ5tE4DTDP
|
||||
fU2SD38VpswioCtco/9ke3zZXXvZqnUhryWMfNjpxNF4E3UVkOsWwvkLV5qODsGr
|
||||
K9+0oXxUYHIfcryF1O7F2Kf0HeHdEP15EB6pwb9qW/YcH/+M06P8zOS4dv7etZKv
|
||||
ntGQevlF3Xw6KNy7PZ3iQgmigctA/MlYHUoNXCRNL2Wq5/QnVTSJbf9p+WN5DHEn
|
||||
p662DRZT/K0pzJETB3/Sqswi86S/+bnggEegPeRzVDz0k3qXgia2S254mxibkD9R
|
||||
7yTYiwIDAQABo1MwUTAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBSoZWaF9pFA
|
||||
JEKZcTGJYnUkf/kFjjAfBgNVHSMEGDAWgBReyxFuGLwIL/Q/dJXUSv51s4my6TAN
|
||||
BgkqhkiG9w0BAQsFAAOCAQEAicFkgSl+smSTM3SK9O4f8OOBtcX1aF1XkLvXHXpt
|
||||
JIXyPkJbW+44Vb8q/ARI/4Nss4AlWuCWy0vHAhhPmvqBl0sr7CL/jAfJTSq++7P3
|
||||
XjfQ/l7hT26DejmqXMZxIF89EwZha0DmetEIYnowvp6oiFluuMGY2qOzF0NXZTAK
|
||||
NvHrj5yT1bpq6qdPLcKszaR9+MYmVC0r4pAargfpjCr01lBRH1h+p5QEEf/tYmQP
|
||||
BY0pWbgI3wnMPtFCD0fPLHhCJXnWTpGeFsAczOaF3YJicCKg+3EusiazwJihzYfY
|
||||
FdTnJlD2KkP2ipIia5q7wja7SeWBV8hzPvEuqvlUW0BCKQ==
|
||||
-----END CERTIFICATE-----
|
18
pkgs/clan-vm-manager/tests/data/vnc-security/tls.csr
Normal file
18
pkgs/clan-vm-manager/tests/data/vnc-security/tls.csr
Normal file
|
@ -0,0 +1,18 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIC4zCCAcsCAQAwfDELMAkGA1UEBhMCVVMxEjAQBgNVBAgMCVlvdXJTdGF0ZTER
|
||||
MA8GA1UEBwwIWW91ckNpdHkxGTAXBgNVBAoMEFlvdXJPcmdhbml6YXRpb24xFzAV
|
||||
BgNVBAsMDllvdXJEZXBhcnRtZW50MRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0G
|
||||
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBhKVHicSPgu41yWZAV+p6LUVT5u8u
|
||||
CDNbM00Z+EaKoCvNXwXuydQZobKYDpltcCP/9n5dcNDm0TgNMM99TZIPfxWmzCKg
|
||||
K1yj/2R7fNlde9mqdSGvJYx82OnE0XgTdRWQ6xbC+QtXmo4Owasr37ShfFRgch9y
|
||||
vIXU7sXYp/Qd4d0Q/XkQHqnBv2pb9hwf/4zTo/zM5Lh2/t61kq+e0ZB6+UXdfDoo
|
||||
3Ls9neJCCaKBy0D8yVgdSg1cJE0vZarn9CdVNIlt/2n5Y3kMcSenrrYNFlP8rSnM
|
||||
kRMHf9KqzCLzpL/5ueCAR6A95HNUPPSTepeCJrZLbnibGJuQP1HvJNiLAgMBAAGg
|
||||
IjAgBgkqhkiG9w0BCQ4xEzARMA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQEL
|
||||
BQADggEBAH8RwLJXJZWq4Q91+/cLP/s8aKge3CK09laDAcWMNDWfvR8+mNlSte7P
|
||||
EwVVL1GJN6ywwy0xCLKCY2Ixb66jfaW6lcphVgWiP0+8l8t/7p0MVRD9Uogf3nut
|
||||
Sj4cyzjUcqR6zK7MYwBEHy+PFURjhpvYcskClmZYSP2WQIzt7ZyYBO95NZ8nTM3t
|
||||
Fr6VUIqs8aiLevQbLhjU8eJCyo20WF2/XiDRyub6tEbz1onU1WwTXuEMsWdL4M78
|
||||
/jbB9GQ+XK48kNluw3URz8sPBU6iilgj4xoEcR/A31ORnaEULL5udLr2akq3sOm8
|
||||
CeibewRVc1nnivi0d+WUi0NvSgPdeuA=
|
||||
-----END CERTIFICATE REQUEST-----
|
28
pkgs/clan-vm-manager/tests/data/vnc-security/tls.key
Normal file
28
pkgs/clan-vm-manager/tests/data/vnc-security/tls.key
Normal file
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBhKVHicSPgu41
|
||||
yWZAV+p6LUVT5u8uCDNbM00Z+EaKoCvNXwXuydQZobKYDpltcCP/9n5dcNDm0TgN
|
||||
MM99TZIPfxWmzCKgK1yj/2R7fNlde9mqdSGvJYx82OnE0XgTdRWQ6xbC+QtXmo4O
|
||||
wasr37ShfFRgch9yvIXU7sXYp/Qd4d0Q/XkQHqnBv2pb9hwf/4zTo/zM5Lh2/t61
|
||||
kq+e0ZB6+UXdfDoo3Ls9neJCCaKBy0D8yVgdSg1cJE0vZarn9CdVNIlt/2n5Y3kM
|
||||
cSenrrYNFlP8rSnMkRMHf9KqzCLzpL/5ueCAR6A95HNUPPSTepeCJrZLbnibGJuQ
|
||||
P1HvJNiLAgMBAAECggEAIJ5Bl53Onlv01+cTD5xh/ub7jQlbXlhug5xRjiONjFc0
|
||||
GuE96EJnuExLhJrNXKduwfmj0g8ufwFb38lO5/F3wZnrpdo5qeK1MkVdg/0GzF2Q
|
||||
Uk18+H8tP2v2d0DRawIsuOkPRJzivwjjkfQt7G7ADQoeVMVXrKi/LCV0/rBMku6Q
|
||||
oIjgY/odhX6w+Xb1RNqvtgvI2VpIQFTrb17GDF+RUVBADjoSNQyeqg/LsNvDne0N
|
||||
7VitPJsdwNjgt6SmSBp/R0rBI3LHgSuk/2/ca9tFbBMmI9PYKQhUbXod14D8i6WH
|
||||
jMsaBKXNeqYkkrXUQFKo2YmIfb5RHMRgxv/CYdxT4QKBgQDhvG9yPPLwfj3Ni76Q
|
||||
4PyQtuHdpD0H35D4pnLQqv18Ec5aIu7sCjG+EJSBLRWD2PPAVieGX5/AyS31pBf3
|
||||
6MUaqISrfGMVtU4egTIoK5fbJDy9w4da/McjxbIIE+UK/hhvOYn6CeVtC9v2VW1i
|
||||
hZlWkyiIlMwcV4QNR6i9aFRJ4QKBgQDbdnKixXCKinNuKLAsu3MXWVBk3YT4u16P
|
||||
+D8FCWm859nV2i69+FFVG7zTvzsvjK41Ya9OGggaK3jrLbEwsNu0R4FVaqSLs34c
|
||||
fdq2ZegU/TUTZvnkWAiQuFd9CEcSGr3qnLEC3nFCuUFLyYLZ80zuYWjOE4vZdrQ8
|
||||
Eu0bHHvn6wKBgBMIpoUFap6opmFshRcGQYWaRhVAQf0l9r1gm5HIuTL69WFYTLkO
|
||||
av9RupPhz0ycwIDZQt/rtDa3P+7UdUjsEaKbzwP+qwQrk3izAB2u/1D1D0IY+JLN
|
||||
eaUkiExyEQAKSNkoCuBQcU3ukA+HSH/kL/fC1Mofcc55+qJ8BlhiMalBAoGASMUu
|
||||
3+A+IAImollliX+iexSHftqhM+TVR0HWi7ICWLw8VBfjteQ3+9OVulTHqE2qmlLI
|
||||
0Un6c8sEbl8ZSP7r6wxmy07wPs6Gu6XTtvV1jjgjuEpGBDxYorwtbm0nO86YOMo6
|
||||
O6xMvAY3q4ynEeQGF2k/Wk3K6pHc06qm6n14bH8CgYEAn86QvwgBRT7zoVO1CPRu
|
||||
hwkaxYctJq72skNzsiNn/uC8GtxQcUWyqIU4Sc3pNDpLYPLeMpTD9E//BCUUAum1
|
||||
kD0LB8e48Lua72LF3fy0XZGKUsmKm5YXqtDf2lh1mPt47c4pMooJrn2f9RBP2cdW
|
||||
7R2cJtcxu+Y4Sgxp2N9EcfE=
|
||||
-----END PRIVATE KEY-----
|
0
pkgs/clan-vm-manager/tests/helpers/__init__.py
Normal file
0
pkgs/clan-vm-manager/tests/helpers/__init__.py
Normal file
2493
pkgs/clan-vm-manager/tests/helpers/libvncclient.py
Normal file
2493
pkgs/clan-vm-manager/tests/helpers/libvncclient.py
Normal file
File diff suppressed because it is too large
Load Diff
312
pkgs/clan-vm-manager/tests/helpers/vnc_client.py
Normal file
312
pkgs/clan-vm-manager/tests/helpers/vnc_client.py
Normal file
|
@ -0,0 +1,312 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import threading
|
||||
from ctypes import (
|
||||
CDLL,
|
||||
POINTER,
|
||||
Structure,
|
||||
addressof,
|
||||
c_char_p,
|
||||
c_int,
|
||||
c_size_t,
|
||||
c_uint8,
|
||||
c_void_p,
|
||||
cast,
|
||||
memmove,
|
||||
sizeof,
|
||||
)
|
||||
from pathlib import Path
|
||||
from typing import TypeVar
|
||||
|
||||
import libvncclient
|
||||
from libvncclient import (
|
||||
GetCredentialProc,
|
||||
GotCursorShapeProc,
|
||||
GotFrameBufferUpdateProc,
|
||||
GotXCutTextProc,
|
||||
HandleKeyboardLedStateProc,
|
||||
HandleRFBServerMessage,
|
||||
MallocFrameBufferProc,
|
||||
SendFramebufferUpdateRequest,
|
||||
SetFormatAndEncodings,
|
||||
String,
|
||||
WaitForMessage,
|
||||
rfbClient,
|
||||
rfbClientCleanup,
|
||||
rfbCredential,
|
||||
rfbCredentialTypeUser,
|
||||
rfbCredentialTypeX509,
|
||||
rfbGetClient,
|
||||
rfbInitClient,
|
||||
struct__rfbClient,
|
||||
)
|
||||
|
||||
path_to_lib = libvncclient._libs["libvncclient.so"].access["cdecl"]._name
|
||||
if path_to_lib.startswith("/nix/store/"):
|
||||
print("Using libvncclient from nix store")
|
||||
|
||||
|
||||
|
||||
libc = CDLL("libc.so.6") # Use the correct path for your libc
|
||||
libc.malloc.argtypes = [c_size_t]
|
||||
libc.malloc.restype = c_void_p
|
||||
|
||||
|
||||
def alloc_str(data: str) -> c_char_p:
|
||||
bdata = data.encode("ascii") + b"\0"
|
||||
data_buf = libc.malloc(len(bdata)) # +1 for null terminator
|
||||
|
||||
memmove(data_buf, c_char_p(bdata), len(bdata))
|
||||
|
||||
return data_buf
|
||||
|
||||
|
||||
StructType = TypeVar("StructType", bound="Structure")
|
||||
|
||||
|
||||
def got_cursor_shape(
|
||||
cl: rfbClient,
|
||||
width: int,
|
||||
height: int,
|
||||
xhot: int,
|
||||
yhot: int,
|
||||
data: POINTER(c_uint8), # type: ignore[valid-type]
|
||||
) -> None:
|
||||
print(f"got_cursor_shape: {width} {height} {xhot} {yhot}")
|
||||
return
|
||||
|
||||
|
||||
def alloc_struct(data: StructType) -> int:
|
||||
data_buf = libc.malloc(sizeof(data))
|
||||
memmove(data_buf, addressof(data), sizeof(data))
|
||||
return data_buf
|
||||
|
||||
|
||||
def get_credential(
|
||||
rfb_client: POINTER(struct__rfbClient), # type: ignore[valid-type]
|
||||
credential_type: c_int,
|
||||
) -> int | None:
|
||||
print(f"==> get_credential: {credential_type}")
|
||||
|
||||
if credential_type == rfbCredentialTypeUser:
|
||||
creds = rfbCredential()
|
||||
username = os.environ.get("USER")
|
||||
if not username:
|
||||
print("ERROR: USER environment variable is not set")
|
||||
return None
|
||||
creds.userCredential.username = alloc_str(username)
|
||||
creds.userCredential.password = None
|
||||
creds_buf = alloc_struct(creds)
|
||||
|
||||
# Return a integer to the creds obj
|
||||
return creds_buf
|
||||
|
||||
if credential_type == rfbCredentialTypeX509:
|
||||
ca_dir = (
|
||||
Path(os.environ.get("GIT_ROOT", ""))
|
||||
/ "pkgs"
|
||||
/ "clan-vm-manager"
|
||||
/ "tests"
|
||||
/ "data"
|
||||
/ "vnc-security"
|
||||
)
|
||||
ca_cert = ca_dir / "ca.crt"
|
||||
if not ca_cert.exists():
|
||||
print(f"ERROR: ca_cert does not exist: {ca_cert}")
|
||||
return None
|
||||
ca_crl = ca_dir / "ca.key"
|
||||
if not ca_crl.exists():
|
||||
print(f"ERROR: ca_crl does not exist: {ca_crl}")
|
||||
return None
|
||||
|
||||
# Instantiate the credential union and populate it
|
||||
creds = rfbCredential()
|
||||
creds.x509Credential.x509CACertFile = alloc_str(str(ca_cert))
|
||||
creds.x509Credential.x509CrlVerifyMode = False
|
||||
print("===> Alloc struct")
|
||||
creds_buf = alloc_struct(creds)
|
||||
print("====> Done alloc struct")
|
||||
|
||||
# Return a integer to the creds obj
|
||||
return creds_buf
|
||||
|
||||
print(f"ERROR: Unknown credential type: {credential_type}")
|
||||
return None
|
||||
|
||||
|
||||
def got_selection(cl: rfbClient, text: str, text_len: int) -> None:
|
||||
print(f"got_selection: {text}")
|
||||
|
||||
|
||||
def resize(client: rfbClient) -> bool:
|
||||
width = client.contents.width
|
||||
height = client.contents.height
|
||||
bits_per_pixel = client.contents.format.bitsPerPixel
|
||||
print(f"Size: {width}x{height}")
|
||||
|
||||
if client.contents.frameBuffer:
|
||||
libc.free(client.contents.frameBuffer)
|
||||
client.contents.frameBuffer = None
|
||||
|
||||
new_buf = libc.malloc(int(width * height * bits_per_pixel / 8))
|
||||
if not new_buf:
|
||||
print("malloc failed")
|
||||
return False
|
||||
|
||||
casted_buf = cast(new_buf, POINTER(c_uint8))
|
||||
client.contents.frameBuffer = casted_buf
|
||||
|
||||
request = SendFramebufferUpdateRequest(client, 0, 0, width, height, False)
|
||||
if not request:
|
||||
print("SendFramebufferUpdateRequest failed")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def update(cl: rfbClient, x: int, y: int, w: int, h: int) -> None:
|
||||
print(f"update: {x} {y} {w} {h}")
|
||||
return
|
||||
|
||||
|
||||
def kbd_leds(cl: rfbClient, value: int, pad: int) -> None:
|
||||
print(f"kbd_leds: {value} {pad}")
|
||||
|
||||
|
||||
# /*****************************************************************************
|
||||
# *
|
||||
# * Encoding types
|
||||
# *
|
||||
# *****************************************************************************/
|
||||
|
||||
# #define rfbEncodingRaw 0
|
||||
# #define rfbEncodingCopyRect 1
|
||||
# #define rfbEncodingRRE 2
|
||||
# #define rfbEncodingCoRRE 4
|
||||
# #define rfbEncodingHextile 5
|
||||
# #define rfbEncodingZlib 6
|
||||
# #define rfbEncodingTight 7
|
||||
# #define rfbEncodingTightPng 0xFFFFFEFC /* -260 */
|
||||
# #define rfbEncodingZlibHex 8
|
||||
# #define rfbEncodingUltra 9
|
||||
# #define rfbEncodingTRLE 15
|
||||
# #define rfbEncodingZRLE 16
|
||||
# #define rfbEncodingZYWRLE 17
|
||||
|
||||
# #define rfbEncodingH264 0x48323634
|
||||
|
||||
# /* Cache & XOR-Zlib - rdv@2002 */
|
||||
# #define rfbEncodingCache 0xFFFF0000
|
||||
# #define rfbEncodingCacheEnable 0xFFFF0001
|
||||
# #define rfbEncodingXOR_Zlib 0xFFFF0002
|
||||
# #define rfbEncodingXORMonoColor_Zlib 0xFFFF0003
|
||||
# #define rfbEncodingXORMultiColor_Zlib 0xFFFF0004
|
||||
# #define rfbEncodingSolidColor 0xFFFF0005
|
||||
# #define rfbEncodingXOREnable 0xFFFF0006
|
||||
# #define rfbEncodingCacheZip 0xFFFF0007
|
||||
# #define rfbEncodingSolMonoZip 0xFFFF0008
|
||||
# #define rfbEncodingUltraZip 0xFFFF0009
|
||||
|
||||
|
||||
class VncError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class VncClient:
|
||||
client: rfbClient
|
||||
stop_event: threading.Event
|
||||
thread: threading.Thread | None
|
||||
|
||||
def __init__(self) -> None:
|
||||
bits_per_sample = 8
|
||||
samples_per_pixel = 3
|
||||
bytes_per_pixel = 4
|
||||
self.client: rfbClient = rfbGetClient(
|
||||
bits_per_sample, samples_per_pixel, bytes_per_pixel
|
||||
)
|
||||
if not self.client:
|
||||
raise VncError("rfbGetClient failed")
|
||||
|
||||
self.stop_event = threading.Event() # Initialize the stop event.
|
||||
self.thread = None
|
||||
|
||||
self._client_settings()
|
||||
self._set_color()
|
||||
self._set_encoding()
|
||||
|
||||
def _client_settings(self) -> None:
|
||||
# client settings
|
||||
self.client.contents.MallocFrameBuffer = MallocFrameBufferProc(resize)
|
||||
self.client.contents.canHandleNewFBSize = True
|
||||
self.client.contents.GotFrameBufferUpdate = GotFrameBufferUpdateProc(update)
|
||||
self.client.contents.HandleKeyboardLedState = HandleKeyboardLedStateProc(
|
||||
kbd_leds
|
||||
)
|
||||
self.client.contents.GotXCutText = GotXCutTextProc(got_selection)
|
||||
self.client.contents.GotCursorShape = GotCursorShapeProc(got_cursor_shape)
|
||||
self.client.contents.GetCredential = GetCredentialProc(get_credential)
|
||||
self.client.contents.listenPort = 5900
|
||||
self.client.contents.listenAddress = String.from_param("127.0.0.1")
|
||||
|
||||
def _set_color(self) -> None:
|
||||
# Set client encoding to (equal to remmina)
|
||||
# TRUE colour: max red 255 green 255 blue 255, shift red 16 green 8 blue 0
|
||||
self.client.contents.format.bitsPerPixel = 32
|
||||
self.client.contents.format.depth = 24
|
||||
self.client.contents.format.redShift = 16
|
||||
self.client.contents.format.blueShift = 0
|
||||
self.client.contents.format.greenShift = 8
|
||||
self.client.contents.format.blueMax = 0xFF
|
||||
self.client.contents.format.redMax = 0xFF
|
||||
self.client.contents.format.greenMax = 0xFF
|
||||
SetFormatAndEncodings(self.client)
|
||||
|
||||
def _set_encoding(self) -> None:
|
||||
# Set client compression to remminas quality 9 (best) and compress level 1 (lowest)
|
||||
# BUG: tight encoding is crashing (looks exploitable)
|
||||
self.client.contents.appData.shareDesktop = True
|
||||
self.client.contents.appData.useBGR233 = False
|
||||
self.client.contents.appData.encodingsString = String.from_param(
|
||||
"copyrect zlib hextile raw"
|
||||
)
|
||||
self.client.contents.appData.compressLevel = 1
|
||||
self.client.contents.appData.qualityLevel = 9
|
||||
SetFormatAndEncodings(self.client)
|
||||
|
||||
def start_blocking(self) -> None:
|
||||
print("Initializing connection")
|
||||
argc = c_int(0)
|
||||
argv = None
|
||||
if not rfbInitClient(self.client, argc, argv):
|
||||
raise VncError("rfbInitClient failed")
|
||||
|
||||
# Main loop
|
||||
while not self.stop_event.is_set():
|
||||
res = WaitForMessage(self.client, 500)
|
||||
if res < 0:
|
||||
rfbClientCleanup(self.client)
|
||||
raise VncError("WaitForMessage failed")
|
||||
|
||||
if res > 0:
|
||||
if not HandleRFBServerMessage(self.client):
|
||||
rfbClientCleanup(self.client)
|
||||
raise VncError("HandleRFBServerMessage failed")
|
||||
|
||||
rfbClientCleanup(self.client)
|
||||
|
||||
def start(self) -> None:
|
||||
self.thread = threading.Thread(target=self.start_blocking)
|
||||
self.thread.start()
|
||||
|
||||
def stop(self) -> None:
|
||||
self.stop_event.set() # Signal the thread to stop.
|
||||
if self.thread is not None:
|
||||
self.thread.join() # Wait for the thread to finish.
|
||||
print("VNC client stopped.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
vnc = VncClient()
|
||||
vnc.start()
|
||||
assert vnc.thread is not None
|
||||
vnc.thread.join()
|
5
pkgs/clan-vm-manager/tests/pygdb.sh
Executable file
5
pkgs/clan-vm-manager/tests/pygdb.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
|
||||
PYTHON_DIR=$(dirname "$(which python3)")/..
|
||||
gdb --quiet -ex "source $PYTHON_DIR/share/gdb/libpython.py" -ex "run" --args python "$1"
|
|
@ -16,12 +16,21 @@ def temporary_home(monkeypatch: pytest.MonkeyPatch) -> Iterator[Path]:
|
|||
path = Path(env_dir).resolve()
|
||||
log.debug("Temp HOME directory: %s", str(path))
|
||||
monkeypatch.setenv("HOME", str(path))
|
||||
monkeypatch.setenv("XDG_CONFIG_HOME", str(path / ".config"))
|
||||
runtime_dir = path / "xdg-runtime-dir"
|
||||
runtime_dir.mkdir()
|
||||
runtime_dir.chmod(0o700)
|
||||
monkeypatch.setenv("XDG_RUNTIME_DIR", str(runtime_dir))
|
||||
monkeypatch.chdir(str(path))
|
||||
yield path
|
||||
else:
|
||||
with tempfile.TemporaryDirectory(prefix="pytest-") as dirpath:
|
||||
monkeypatch.setenv("HOME", str(dirpath))
|
||||
monkeypatch.setenv("XDG_CONFIG_HOME", str(Path(dirpath) / ".config"))
|
||||
runtime_dir = Path(dirpath) / "xdg-runtime-dir"
|
||||
runtime_dir.mkdir()
|
||||
runtime_dir.chmod(0o700)
|
||||
monkeypatch.setenv("XDG_RUNTIME_DIR", str(runtime_dir))
|
||||
monkeypatch.chdir(str(dirpath))
|
||||
log.debug("Temp HOME directory: %s", str(dirpath))
|
||||
yield Path(dirpath)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
from cli import Cli
|
||||
from helpers.cli import Cli
|
||||
|
||||
|
||||
def test_help(capfd: pytest.CaptureFixture) -> None:
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import time
|
||||
|
||||
from wayland import GtkProc
|
||||
from wayland import GtkApp
|
||||
|
||||
|
||||
def test_open(app: GtkProc) -> None:
|
||||
time.sleep(0.5)
|
||||
assert app.poll() is None
|
||||
def test_join(app: GtkApp) -> None:
|
||||
while app.poll() is None:
|
||||
time.sleep(0.1)
|
||||
assert True
|
||||
|
|
13
pkgs/clan-vm-manager/tests/vnc.sh
Executable file
13
pkgs/clan-vm-manager/tests/vnc.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
||||
# For vnc debugging
|
||||
export VNC_USERNAME="$USER"
|
||||
export VNC_PASSWORD=""
|
||||
|
||||
CA_CRT=$GIT_ROOT/pkgs/clan-vm-manager/tests/data/vnc-security/ca.crt
|
||||
|
||||
vncviewer 127.0.0.1 -Shared -X509CA "$CA_CRT"
|
||||
|
|
@ -1,27 +1,137 @@
|
|||
# Import necessary modules
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from collections.abc import Generator
|
||||
from subprocess import Popen
|
||||
from typing import NewType
|
||||
from pathlib import Path
|
||||
|
||||
# Assuming NewType is already imported or defined somewhere
|
||||
import pytest
|
||||
from helpers.vnc_client import VncClient
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def wayland_compositor() -> Generator[Popen, None, None]:
|
||||
# Start the Wayland compositor (e.g., Weston)
|
||||
# compositor = Popen(["weston", "--backend=headless-backend.so"])
|
||||
compositor = Popen(["weston"])
|
||||
yield compositor
|
||||
# Cleanup: Terminate the compositor
|
||||
compositor.terminate()
|
||||
def write_script(cmd: list[str], new_env: dict[str, str], name: str) -> None:
|
||||
# Create the bash script content
|
||||
script_content = "#!/bin/bash\n"
|
||||
for key, value in new_env.items():
|
||||
if '"' in value:
|
||||
value = value.replace('"', '\\"')
|
||||
if "'" in value:
|
||||
value = value.replace("'", "\\'")
|
||||
if "`" in value:
|
||||
value = value.replace("`", "\\`")
|
||||
script_content += f'export {key}="{value}"\n'
|
||||
strace_cmd = ["strace", "-f", "-o", "file-access.log", "-e", "trace=file", *cmd]
|
||||
script_content += shlex.join(strace_cmd)
|
||||
|
||||
# Write the bash script to a file
|
||||
script_filename = name
|
||||
with open(script_filename, "w") as script_file:
|
||||
script_file.write(script_content)
|
||||
|
||||
print(f"You can find the script at {os.getcwd()}/{script_filename}")
|
||||
# Make the script executable
|
||||
os.chmod(script_filename, 0o755)
|
||||
|
||||
|
||||
GtkProc = NewType("GtkProc", Popen)
|
||||
class Compositor:
|
||||
def __init__(self, proc: subprocess.Popen, env: dict[str, str]) -> None:
|
||||
self.proc = proc
|
||||
self.env = env
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def app() -> Generator[GtkProc, None, None]:
|
||||
rapp = Popen([sys.executable, "-m", "clan_vm_manager"], text=True)
|
||||
yield GtkProc(rapp)
|
||||
# Cleanup: Terminate your application
|
||||
rapp.terminate()
|
||||
@pytest.fixture
|
||||
def weston_override_lib(
|
||||
temporary_home: Path, test_root: Path
|
||||
) -> Generator[Path, None, None]:
|
||||
# with TemporaryDirectory() as tmpdir:
|
||||
# This enforces a login shell by overriding the login shell of `getpwnam(3)`
|
||||
lib_path = Path(temporary_home) / "libweston_auth_override.so"
|
||||
subprocess.run(
|
||||
[
|
||||
os.environ.get("CC", "cc"),
|
||||
"-shared",
|
||||
"-fPIC",
|
||||
"-o",
|
||||
lib_path,
|
||||
str(test_root / "weston_auth_override.c"),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
yield lib_path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def wayland_comp(
|
||||
test_root: Path, weston_override_lib: Path
|
||||
) -> Generator[Compositor, None, None]:
|
||||
tls_key = test_root / "data" / "vnc-security" / "tls.key"
|
||||
tls_cert = test_root / "data" / "vnc-security" / "tls.crt"
|
||||
wayland_display = "wayland-1" # Define a unique WAYLAND_DISPLAY value
|
||||
new_env = os.environ.copy()
|
||||
new_env["WAYLAND_DISPLAY"] = wayland_display
|
||||
# Uncomment the next line if you need to force software rendering
|
||||
new_env["LIBGL_ALWAYS_SOFTWARE"] = "true"
|
||||
new_env["LD_PRELOAD"] = str(weston_override_lib)
|
||||
cmd = [
|
||||
"weston",
|
||||
"--debug",
|
||||
"--width=1920",
|
||||
"--height=1080",
|
||||
"--port=5900",
|
||||
f"--vnc-tls-key={tls_key}",
|
||||
f"--vnc-tls-cert={tls_cert}",
|
||||
"--backend=vnc",
|
||||
f"--socket={wayland_display}",
|
||||
]
|
||||
|
||||
compositor = subprocess.Popen(cmd, env=new_env, text=True)
|
||||
time.sleep(0.4)
|
||||
if compositor.poll() is not None:
|
||||
raise Exception(f"Failed to start {cmd}")
|
||||
client = VncClient()
|
||||
client.start()
|
||||
yield Compositor(compositor, new_env)
|
||||
compositor.kill()
|
||||
client.stop()
|
||||
|
||||
|
||||
class GtkApp:
|
||||
def __init__(self, proc: subprocess.Popen) -> None:
|
||||
self.proc = proc
|
||||
|
||||
def kill(self) -> None:
|
||||
self.proc.kill()
|
||||
|
||||
def wait(self) -> None:
|
||||
self.proc.wait()
|
||||
|
||||
def poll(self) -> int | None:
|
||||
return self.proc.poll()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app(wayland_comp: Compositor) -> Generator[GtkApp, None, None]:
|
||||
# Define the new environment variables
|
||||
new_env = wayland_comp.env
|
||||
new_env["GDK_BACKEND"] = "wayland"
|
||||
|
||||
# Define the command to be executed
|
||||
cmd = [f"{sys.executable}", "-m", "clan_vm_manager"]
|
||||
|
||||
write_script(cmd, new_env, "weston.sh")
|
||||
breakpoint()
|
||||
# Execute the script
|
||||
rapp = subprocess.Popen(
|
||||
cmd,
|
||||
text=True,
|
||||
env=new_env,
|
||||
stdin=sys.stdin,
|
||||
)
|
||||
time.sleep(0.4)
|
||||
if rapp.poll() is not None:
|
||||
raise Exception(f"Failed to start {cmd}")
|
||||
yield GtkApp(rapp)
|
||||
rapp.kill()
|
||||
|
|
12
pkgs/clan-vm-manager/tests/weston_auth_override.c
Normal file
12
pkgs/clan-vm-manager/tests/weston_auth_override.c
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
||||
|
||||
// Overriding the weston_authenticate_user function
|
||||
bool weston_authenticate_user(const char *username, const char *password) {
|
||||
printf("=====>Overridden weston_authenticate_user called with username: %s\n", username);
|
||||
return true; // Always return true
|
||||
}
|
Loading…
Reference in New Issue
Block a user