5

I have following docker-compose file for local development:

version: '3.4'

networks:
  mynetwork:

services:
  samba:
    image: instantlinux/samba-dc:latest
    container_name: samba-dc
    cap_add:
      - CAP_SYS_ADMIN
    hostname: my.org
    environment:
      DOMAIN_ACTION: provision
      REALM: my.org
    volumes:
      - etc:/etc/samba
      - lib:/var/lib/samba
    ports:
      - "53:53"
      - "53:53/udp"
      - "88:88"
      - "88:88/udp"
      - "389:389"
    secrets:
      - samba-admin-password

volumes:
  etc:
  lib:

secrets:
  samba-admin-password:
    file: secrets.yaml

Now I try to implement integration tests using testContainers for that purpose:

@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
....


       init {
            try {
                val ldapContainer =
                    GenericContainer("instantlinux/samba-dc:latest")
                        .withEnv("DOMAIN_ACTION", "provision")
                        .withEnv("REALM", "my.company")
                        .withEnv("ADMIN_PASSWORD_SECRET", "samba-admin-password")
                        .withExposedPorts(53, 88, 389)                    
                ldapContainer.start()
                print("Containers has started")
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

But when I try to run it I receive an error:

Container startup failed for image instantlinux/samba-dc:latest
....
rg.testcontainers.containers.GenericContainer expected the predicate to return <true> but it returned <false> for input of <InspectContainerResponse(args=[], config=ContainerConfig(attachStderr=false, attachStdin=false, attachStdout=false, cmd=null, domainName=, entrypoint=[/usr/local/bin/entrypoint.sh], env=[DOMAIN_ACTION=provision, ADMIN_PASSWORD_SECRET=samba-admin-password, REALM=my.company, PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, ALLOW_DNS_UPDATES=secure, BIND_INTERFACES_ONLY=yes, DOMAIN_LOGONS=yes, DOMAIN_MASTER=no, INTERFACES=lo eth0, LOG_LEVEL=1, MODEL=standard, NETBIOS_NAME=, SERVER_STRING=Samba Domain Controller, TZ=UTC, WINBIND_USE_DEFAULT_DOMAIN=yes, WORKGROUP=AD], exposedPorts=....
...
17:01:51.548 [Test worker] ERROR tc.instantlinux/samba-dc:latest -- Log output from the failed container:
Set timezone
Cannot read secret $ADMIN_PASSWORD_SECRET in /run/secrets

Looks like I have to configure secrets somehow but I don' see a way how to acheve it.

Update 1

Secret file looks like this:

kind: Secret
apiVersion: v1
metadata:
  name: samba-admin-password
data:
  ADMIN_PASSWORD_SECRET: superpassword

Update 2

Based on VonC answer I've created the example:

@Testcontainers
@SpringBootTest(webEnvironment = RANDOM_PORT)
@ActiveProfiles("test")
class TestContainersBase {

    @Test
    fun test() {
        val mapper = ObjectMapper(YAMLFactory())
        val secretPathOnHost = "C:\\work\\MyApp\\docker\\secrets.yaml"
        val secretsFile = File(secretPathOnHost)

        val secretsData: Map<String, Any> = mapper.readValue(secretsFile, object: TypeReference<Map<String, Any>>(){})

        // Extract the secret from the parsed data
        val adminPassword = (secretsData["data"] as Map<*,*>?)!!["ADMIN_PASSWORD_SECRET"] as String?

        val secretPathInContainer = "/run/secrets/samba-admin-password";
        // Create and start the container
        val ldapContainer = GenericContainer("instantlinux/samba-dc:latest")
            .withEnv("DOMAIN_ACTION", "provision")
            .withEnv("REALM", "my.company")
            .withEnv("ADMIN_PASSWORD_SECRET", adminPassword) // Set the extracted secret as an environment variable
            .withExposedPorts(53, 88, 389)
            .withFileSystemBind(secretPathOnHost, secretPathInContainer, BindMode.READ_ONLY);

        ldapContainer.start()

        print("qwerty")
        
        Thread.sleep(100000000)

    }
}

In app logs I see:

2023-08-21T13:38:50.555+03:00  INFO 15136 --- [    Test worker] o.t.utility.ImageNameSubstitutor         : Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
2023-08-21T13:38:51.739+03:00  INFO 15136 --- [    Test worker] o.t.d.DockerClientProviderStrategy       : Loaded org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first
2023-08-21T13:38:52.779+03:00  INFO 15136 --- [    Test worker] o.t.d.DockerClientProviderStrategy       : Found Docker environment with local Npipe socket (npipe:////./pipe/docker_engine)
2023-08-21T13:38:52.784+03:00  INFO 15136 --- [    Test worker] org.testcontainers.DockerClientFactory   : Docker host IP address is localhost
2023-08-21T13:38:52.814+03:00  INFO 15136 --- [    Test worker] org.testcontainers.DockerClientFactory   : Connected to docker: 
  Server Version: 20.10.21
  API Version: 1.41
  Operating System: Docker Desktop
  Total Memory: 38292 MB
2023-08-21T13:38:52.889+03:00  INFO 15136 --- [    Test worker] tc.testcontainers/ryuk:0.4.0             : Creating container for image: testcontainers/ryuk:0.4.0
2023-08-21T13:38:53.928+03:00  INFO 15136 --- [    Test worker] o.t.utility.RegistryAuthLocator          : Credential helper/store (docker-credential-desktop) does not have credentials for https://index.docker.io/v1/
2023-08-21T13:38:54.201+03:00  INFO 15136 --- [    Test worker] tc.testcontainers/ryuk:0.4.0             : Container testcontainers/ryuk:0.4.0 is starting: b4a10e2647f83d6fc404644fb09edabf930e987e2c5d138eb3d1b9414b1400ac
2023-08-21T13:38:55.320+03:00  INFO 15136 --- [    Test worker] tc.testcontainers/ryuk:0.4.0             : Container testcontainers/ryuk:0.4.0 started in PT2.488268S
2023-08-21T13:38:55.330+03:00  INFO 15136 --- [    Test worker] o.t.utility.RyukResourceReaper           : Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
2023-08-21T13:38:55.330+03:00  INFO 15136 --- [    Test worker] org.testcontainers.DockerClientFactory   : Checking the system...
2023-08-21T13:38:55.332+03:00  INFO 15136 --- [    Test worker] org.testcontainers.DockerClientFactory   : ?? Docker server version should be at least 1.6.0
2023-08-21T13:38:55.334+03:00  INFO 15136 --- [    Test worker] tc.instantlinux/samba-dc:latest          : Creating container for image: instantlinux/samba-dc:latest
2023-08-21T13:38:56.834+03:00  INFO 15136 --- [    Test worker] tc.instantlinux/samba-dc:latest          : Container instantlinux/samba-dc:latest is starting: 496246f47398809c3a7327b0c73a9b7d7fbe6440865b1cad4c124849f6069acb
2023-08-21T13:39:07.361+03:00  WARN 15136 --- [ntainers-wait-0] .c.w.i.InternalCommandPortListeningCheck : An exception while executing the internal check: Container.ExecResult(exitCode=137, stdout=, stderr=/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
/bin/sh: /bin/bash: not found
)
2023-08-21T13:39:07.367+03:00  INFO 15136 --- [    Test worker] tc.instantlinux/samba-dc:latest          : Container instantlinux/samba-dc:latest started in PT12.0305603S

In docker desktop:

enter image description here

And the first container(based on ports I think that it is Samba) logs:

2023-08-21 13:38:58 Set timezone
2023-08-21 13:38:59 INFO 2023-08-21 10:38:59,067 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2108: Looking up IPv4 addresses
2023-08-21 13:38:59 INFO 2023-08-21 10:38:59,068 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2125: Looking up IPv6 addresses
2023-08-21 13:38:59 WARNING 2023-08-21 10:38:59,068 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2132: No IPv6 address will be assigned
2023-08-21 13:38:59 INFO 2023-08-21 10:38:59,721 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2274: Setting up share.ldb
2023-08-21 13:38:59 INFO 2023-08-21 10:38:59,874 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2278: Setting up secrets.ldb
2023-08-21 13:38:59 INFO 2023-08-21 10:38:59,936 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2283: Setting up the registry
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,304 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2286: Setting up the privileges database
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,466 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2289: Setting up idmap db
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,555 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #2296: Setting up SAM db
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,573 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #880: Setting up sam.ldb partitions and settings
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,574 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #892: Setting up sam.ldb rootDSE
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,591 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1305: Pre-loading the Samba 4 and AD schema
2023-08-21 13:39:00 Unable to determine the DomainSID, can not enforce uniqueness constraint on local domainSIDs
2023-08-21 13:39:00 
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,638 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1383: Adding DomainDN: DC=my,DC=company
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,659 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1415: Adding configuration container
2023-08-21 13:39:00 INFO 2023-08-21 10:39:00,678 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1430: Setting up sam.ldb schema
2023-08-21 13:39:03 INFO 2023-08-21 10:39:03,229 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1448: Setting up sam.ldb configuration data
2023-08-21 13:39:03 INFO 2023-08-21 10:39:03,356 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1489: Setting up display specifiers
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,522 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1497: Modifying display specifiers and extended rights
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,569 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1504: Adding users container
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,570 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1510: Modifying users container
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,571 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1513: Adding computers container
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,572 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1519: Modifying computers container
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,574 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1523: Setting up sam.ldb data
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,728 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1553: Setting up well known security principals
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,770 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1567: Setting up sam.ldb users and groups
2023-08-21 13:39:05 INFO 2023-08-21 10:39:05,993 pid:18 /usr/lib/python3.10/site-packages/samba/provision/__init__.py #1575: Setting up self join
2023-08-21 13:39:06 Repacking database from v1 to v2 format (first record CN=Structural-Object-Class,CN=Schema,CN=Configuration,DC=my,DC=company)
2023-08-21 13:39:06 Repack: re-packed 10000 records so far
2023-08-21 13:39:06 Repacking database from v1 to v2 format (first record CN=nTDSSiteSettings-Display,CN=406,CN=DisplaySpecifiers,CN=Configuration,DC=my,DC=company)
2023-08-21 13:39:06 Repacking database from v1 to v2 format (first record CN=ObjectMoveTable,CN=FileLinks,CN=System,DC=my,DC=company)
2023-08-21 13:39:07 set_nt_acl_no_snum: fset_nt_acl returned NT_STATUS_ACCESS_DENIED.
2023-08-21 13:39:07 ERROR(runtime): uncaught exception - (3221225506, '{Access Denied} A process has requested access to an object but has not been granted those access rights.')
2023-08-21 13:39:07   File "/usr/lib/python3.10/site-packages/samba/netcmd/__init__.py", line 186, in _run
2023-08-21 13:39:07     return self.run(*args, **kwargs)
2023-08-21 13:39:07   File "/usr/lib/python3.10/site-packages/samba/netcmd/domain.py", line 493, in run
2023-08-21 13:39:07     result = provision(self.logger,
2023-08-21 13:39:07   File "/usr/lib/python3.10/site-packages/samba/provision/__init__.py", line 2325, in provision
2023-08-21 13:39:07     provision_fill(samdb, secrets_ldb, logger, names, paths,
2023-08-21 13:39:07   File "/usr/lib/python3.10/site-packages/samba/provision/__init__.py", line 1965, in provision_fill
2023-08-21 13:39:07     setsysvolacl(samdb, paths.netlogon, paths.sysvol, paths.root_uid,
2023-08-21 13:39:07   File "/usr/lib/python3.10/site-packages/samba/provision/__init__.py", line 1742, in setsysvolacl
2023-08-21 13:39:07     _setntacl(sysvol)
2023-08-21 13:39:07   File "/usr/lib/python3.10/site-packages/samba/provision/__init__.py", line 1736, in _setntacl
2023-08-21 13:39:07     return setntacl(
2023-08-21 13:39:07   File "/usr/lib/python3.10/site-packages/samba/ntacls.py", line 228, in setntacl
2023-08-21 13:39:07     smbd.set_nt_acl(

docker ps

PS C:\work\myApp\docker> docker ps
CONTAINER ID   IMAGE                       COMMAND       CREATED          STATUS          PORTS                     NAMES
5541e9f96005   testcontainers/ryuk:0.4.0   "/bin/ryuk"   24 seconds ago   Up 23 seconds   0.0.0.0:64762->8080/tcp   testcontainers-ryuk-6d02415f-7042-4de8-bf0d-a1be71ea5172
PS C:\work\myApp\docker>
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • Can you share how `secrets.yaml` looks like? – Robin Thomas Aug 19 '23 at 12:45
  • @Robin Thomas updated the topic - please take a look. Also more details could be found here: https://github.com/instantlinux/docker-tools/tree/main/images/samba-dc – gstackoverflow Aug 21 '23 at 07:22
  • 1
    @gstackoverflow OK, I have edited the answer to take into account the secret file you have included in your question. – VonC Aug 21 '23 at 07:33

1 Answers1

3

Testcontainers does not seem to support Docker Compose's secrets directly. The only notion of secret is when using a HashiCorp Vault Module .withSecretInVault().

In your case, you can try and use a volume to emulate a secret: it is a workaround, a volume to bind-mount your secrets into the container at the expected path.

val secretPathOnHost = "/path/to/your/secrets.yaml";
val secretPathInContainer = "/run/secrets/samba-admin-password";

val ldapContainer = GenericContainer("instantlinux/samba-dc:latest")
    .withEnv("DOMAIN_ACTION", "provision")
    .withEnv("REALM", "my.company")
    .withEnv("ADMIN_PASSWORD_SECRET", "samba-admin-password")
    .withExposedPorts(53, 88, 389)
    .withFileSystemBind(secretPathOnHost, secretPathInContainer, BindMode.READ_ONLY);

ldapContainer.start();

Do replace /path/to/your/secrets.yaml with the absolute path to your secrets.yaml file on the host machine.

Note: Emulating secrets as volumes means the secret is available as a plaintext file on your host system, so make sure you manage its permissions and access properly. That might be fine for local development and testing, but might not be ideal for production-like environments.

And... never commit secrets or secret paths to source control.


Since the secret file is:

kind: Secret
apiVersion: v1
metadata:
  name: samba-admin-password
data:
  ADMIN_PASSWORD_SECRET: superpassword

Given this format, which is similar to a Kubernetes secret, you will need to parse the file in your test setup and then set the secret as an environment variable to the container.

Using testcontainers and the Jackson library for YAML parsing:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.File;
import java.util.Map;

// ...

// Load and parse the secrets.yaml file
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
File secretsFile = new File("/path/to/your/secrets.yaml");
Map<String, Object> secretsData = mapper.readValue(secretsFile, Map.class);

// Extract the secret from the parsed data
String adminPassword = (String) ((Map) secretsData.get("data")).get("ADMIN_PASSWORD_SECRET");

// Create and start the container
val ldapContainer = GenericContainer("instantlinux/samba-dc:latest")
    .withEnv("DOMAIN_ACTION", "provision")
    .withEnv("REALM", "my.company")
    .withEnv("ADMIN_PASSWORD_SECRET", adminPassword) // Set the extracted secret as an environment variable
    .withExposedPorts(53, 88, 389);

ldapContainer.start();

That method involves reading the secret into your Java application, which you then pass as an environment variable to the container.


From the example provided by the OP, it looks like a Samba container using Testcontainers in a Spring Boot application. The container seems to be starting correctly as you can see the initialization logs of Samba.

The main problem that samba container shutdown immediately after start(application is hanging on in Thread sleep). Looks like root cause could be find in samba logs:

2023-08-21 13:39:07 ERROR(runtime): uncaught exception - (3221225506, '{Access Denied} A process has requested access to an object but has not been granted those access rights.')

Since you are using Docker, remember that the Samba container will have its own user system. You may need to adjust the user or group IDs to match your host system if you are mounting volumes.

Add in your container entry point the id -a and ls -alrth /path/to/your/secrets.yaml commands to see who you are inside the container, and how you see the mounted file system.
Check the ownership and permissions of any volumes you have mounted into the container. The UID and GID inside the container might differ from those outside, leading to permission issues.

If you are running Samba inside a Docker container, ensure that you have provided all necessary capabilities using --cap-add if needed.

Review your Samba configuration (smb.conf). Ensure that the shares and paths defined have the correct permissions.
Also, check for any valid users, read list, or write list directives and ensure that the users listed have the appropriate permissions.

And if you are running a system with SELinux enabled, this can cause permission issues. You can temporarily set SELinux to permissive mode to see if it resolves the issue:

sudo setenforce 0

If this resolves the issue, you will need to create the appropriate SELinux policies or adjust the context for the Samba-related files and directories.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Could you please take a look an update of my topic ? – gstackoverflow Aug 21 '23 at 10:01
  • If I have to create separated topic for that - please let me know – gstackoverflow Aug 21 '23 at 10:45
  • @gstackoverflow I have edited the answer to address your comment. – VonC Aug 21 '23 at 11:29
  • Thank you for you recommendations - the are cool but looks like they don't address my issue I use `Thread.sleep` just to understand what is going on after code execution. It willl be removed as soon I am able to make this thing working. The main problem that samba container shutdown immediately after start(application is hanging on in Thread sleep). Looks like root cause could be find in samba logs: ``` 2023-08-21 13:39:07 ERROR(runtime): uncaught exception - (3221225506, '{Access Denied} A process has requested access to an object but has not been granted those access rights.') ``` – gstackoverflow Aug 21 '23 at 12:05
  • Please take into account that I see this state when test hangs on Thread.sleep https://i.stack.imgur.com/2WJiX.png – gstackoverflow Aug 21 '23 at 12:07
  • @gstackoverflow Can you copy the output of `docker ps`? I can work with text, not with pictures. – VonC Aug 21 '23 at 12:10
  • Yes, sure - copy pasted to the topic – gstackoverflow Aug 21 '23 at 12:17
  • @gstackoverflow I have rewritten the last part of the answer to provide suggestions for addressing the root cause. – VonC Aug 21 '23 at 12:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254988/discussion-between-vonc-and-gstackoverflow). – VonC Aug 21 '23 at 12:20