summary refs log tree commit diff
path: root/issues/CI-CD
diff options
context:
space:
mode:
Diffstat (limited to 'issues/CI-CD')
-rw-r--r--issues/CI-CD/cd-is-slow.gmi276
-rw-r--r--issues/CI-CD/configurations.gmi6
-rw-r--r--issues/CI-CD/development-container-checklist.gmi101
-rw-r--r--issues/CI-CD/failing-services-startup.gmi236
-rw-r--r--issues/CI-CD/profiling-flask.gmi33
-rw-r--r--issues/CI-CD/troubleshooting-within-the-development-container.gmi46
6 files changed, 697 insertions, 1 deletions
diff --git a/issues/CI-CD/cd-is-slow.gmi b/issues/CI-CD/cd-is-slow.gmi
new file mode 100644
index 0000000..9b0e1ee
--- /dev/null
+++ b/issues/CI-CD/cd-is-slow.gmi
@@ -0,0 +1,276 @@
+# CD is slow
+
+The pages are slow and some are broken.
+
+We found out that there are quite a full network calls using DNS - and DNS was slow. The configured DNS server was not responding. Using Google's DNS made things go fast again. We will probably introduce dnsmasq in the container to make things even faster.
+
+# Tags
+
+* type: bug
+* status: in progress
+* priority: high
+* assigned: pjotrp
+* interested: pjotrp, bonfacem
+* keywords: deployment, server
+
+# Tasks
+
+* [ ] Use dnsmasq caching - it is a guix system service
+* [ ] Run less gunicorn processes on CD (2 should do)
+* [ ] Increase debugging output for GN2
+* [ ] Fix GN3 hook for github (it is not working)
+* [X] gn-guile lacks certificates it can use for sparql
+
+# Measuring
+
+bonfacekilz:
+I'm currently instrumenting the requests.  See what hogs up time.  Loading the landing page takes up 32 seconds!
+
+Something's off. From outside the container:
+
+```
+123bonfacem@tux02 ~ $ guix shell python-wrapper python-requests -- python time.py
+Status: 200
+Time taken: 32.989222288131714 seconds
+```
+
+From inside the container:
+
+```
+12025-07-18 14:46:36 INFO:gn2.wqflask:Landing page rendered in 8.12 seconds
+```
+
+And I see:
+
+## CD
+
+```
+> curl -w @- -o /dev/null -s https://cd.genenetwork.org <<EOF
+\n
+DNS lookup:  %{time_namelookup}s\n
+Connect time: %{time_connect}s\n
+TLS handshake: %{time_appconnect}s\n
+Pre-transfer: %{time_pretransfer}s\n
+Start transfer: %{time_starttransfer}s\n
+Total time:   %{time_total}s\n
+EOF
+
+DNS lookup:  8.117543s
+Connect time: 8.117757s
+TLS handshake: 8.197767s
+Pre-transfer: 8.197861s
+Start transfer: 33.096467s
+Total time:   33.096601s
+```
+
+## Production
+```
+> curl -w @- -o /dev/null -s https://genenetwork.org <<EOF
+\n
+DNS lookup:  %{time_namelookup}s\n
+Connect time: %{time_connect}s\n
+TLS handshake: %{time_appconnect}s\n
+Pre-transfer: %{time_pretransfer}s\n
+Start transfer: %{time_starttransfer}s\n
+Total time:   %{time_total}s\n
+EOF
+
+DNS lookup:  8.075794s
+Connect time: 8.076402s
+TLS handshake: 8.147322s
+Pre-transfer: 8.147370s
+Start transfer: 8.797107s
+Total time:   8.797299s
+```
+
+## On tux02 (outside CD container)
+
+```
+> curl -w @- -o /dev/null -s http://localhost:9092 <<EOF
+\n
+DNS lookup:  %{time_namelookup}s\n
+Connect time: %{time_connect}s\n
+TLS handshake: %{time_appconnect}s\n
+Pre-transfer: %{time_pretransfer}s\n
+Start transfer: %{time_starttransfer}s\n
+Total time:   %{time_total}s\n
+EOF
+
+DNS lookup:  0.000068s
+Connect time: 0.000543s
+TLS handshake: 0.000000s
+Pre-transfer: 0.000606s
+Start transfer: 24.851069s
+Total time:   24.851166s
+```
+
+This does not look like an nginx problem (at least on tux02 itself). Also the nginx configuration was not really changed.
+The mysql configuration ditto. I can still test both, but it looks like the problem is inside the system container.
+
+The container logs are at
+
+```
+root@tux02:/export2/guix-containers/genenetwork-development/var/log/cd# tail -100 genenetwork2.log
+```
+
+Some interesting errors there that need resolving, such as
+
+## gn-guile error
+
+```
+tail gn-guile.log
+2025-07-20 04:49:49 X.509 certificate of 'sparql.genenetwork.org' could not be verified:
+2025-07-20 04:49:49   signer-not-found invalid
+```
+
+Guile is not finding the certificates for our virtuoso server. It does work with curl, try
+
+```
+curl -G https://query.wikidata.org/sparql -H "Accept: application/json; charset=utf-8" --data-urlencode query="SELECT DISTINCT * where {
+  wd:Q158695 wdt:P225 ?o .
+} limit 5"
+{
+  "head" : {
+    "vars" : [ "o" ]                                                                                                     },                                                                                                                     "results" : {                                                                                                            "bindings" : [ {                                                                                                         "o" : {
+        "type" : "literal",
+        "value" : "Arabidopsis thaliana"
+      }
+    } ]
+  }
+```
+
+Also inside the container:
+
+```
+curl http://localhost:8091/gene/aliases/Shh
+```
+
+renders the same error! X.509 certificate of 'query.wikidata.org' could not be verified. so it is a gn-guile issue.
+
+## GN2 error reporting
+
+Also there are too many gunicorn processes - and strikingly - no debug output. Also I see a missing robots.txt file (even though LLMs hardly honour them).
+
+Let's try to get inside the container with nsenter:
+
+```
+ps xau|grep genenetwork-development-container
+root     115940  0.0  0.0 163692 26296 ?        Ssl  Jul18   0:00 /gnu/store/ylwk2vn18dkzkj0nxq2h4vjzhz17bm7c-guile-3.0.9/bin/guile --no-auto-compile /usr/local/bin/genenetwork-development-container
+pgrep -P 115940
+115961
+```
+
+Use this child PID and a recent nsenter:
+
+```
+/gnu/store/w7a3frdmffpw3hvxpvvxwxgzfhyqdm6n-profile/bin/nsenter -m -p -t 115961 /run/current-system/profile/bin/bash -login
+```
+
+System tools are in '/run/current-system/profile/bin/'
+
+Make it a one-liner with
+
+```
+/gnu/store/w7a3frdmffpw3hvxpvvxwxgzfhyqdm6n-profile/bin/nsenter -m -p -t $(pgrep -P `ps xau|grep genenetwork-development-container|awk  '{print $2}'|sort -r|head -1`) /run/current-system/profile/bin/bash -login
+```
+
+Once inside we can pick up curl (I note the system container has full access to the /gnu/store on the host:
+
+```
+root@tux02 /# /gnu/store/vdaspmq10c3zmqhp38lfqy812w6r4xg3-curl-8.6.0/bin/curl  -w @- -o /dev/null -s http://localhost:9092 <<EOF
+\n
+DNS lookup:  %{time_namelookup}s\n
+Connect time: %{time_connect}s\n
+TLS handshake: %{time_appconnect}s\n
+Pre-transfer: %{time_pretransfer}s\n
+Start transfer: %{time_starttransfer}s\n
+Total time:   %{time_total}s\n
+EOF
+
+DNS lookup:  0.000064s
+Connect time: 0.000478s
+TLS handshake: 0.000000s
+Pre-transfer: 0.000551s
+Start transfer: 24.792926s
+Total time:   24.793015s
+```
+
+That rules out container and nginx streaming issues.
+
+So the problem is with GN and its DBs. The gn-machines is used from /home/aruni and it checkout is March. Has CD been slow since then? I don't think so. Also the changes to the actual scripts are even older. Also the guix-bioinformatics repo shows no changes. Remaining culprits I suspect are:
+
+* [*] MySQL
+* [ ] Interaction gn-auth with gn2
+* [ ] Interaction gnqa with gn2
+
+Running a standard test on mysql shows it is fine:
+
+```
+time mysql -u webqtlout -pwebqtlout db_webqtl < $rundir/../shared/sql/test02.sql
+Name    FullName        Name    Symbol  CAST(ProbeSet."description" AS BINARY)  CAST(ProbeSet."Probe_Target_Description" AS BINARY)    Chr     Mb      Mean    LRS     Locus   pValue  additive        geno_chr        geno_mb
+HC_M2_0606_P    Hippocampus Consortium M430v2 (Jun06) PDNN      1457545_at      9530036O11Rik   long non-coding RNA, expressed sequence tag (EST) AK035474 with high bladder expression        antisense EST 14 Kb upstream of Shh     5     28.480441        6.7419292929293 15.2845189682605        rsm10000001525  0.055   0.0434848484848485      3       9.671673
+HC_M2_0606_P    Hippocampus Consortium M430v2 (Jun06) PDNN      1427571_at      Shh     sonic hedgehog (hedgehog)     last exon        5       28.457886       6.50113131313131        9.58158655605723        rs8253327       0.697   0.0494097096188748     1       191.908118
+HC_M2_0606_P    Hippocampus Consortium M430v2 (Jun06) PDNN      1436869_at      Shh     sonic hedgehog (hedgehog)     mid distal 3' UTR        5       28.457155       9.279090909090911       12.7711275309832        rs8253327       0.306 -0.214087568058076       1       191.908118
+
+real    0m0.010s
+user    0m0.004s
+sys     0m0.000s
+```
+
+# Profiling CD
+
+Ran a profiler against a traits page.  See the following:
+
+=> /issues/CI-CD/profiling-flask
+
+## Results/Interpretation
+
+* By fixing gn-guile and gene-alias resolution, times dropped by ~10s.  However, the page takes 37.9s to run.
+
+* Resolving a DNS takes around 4.585s.  We make 7 requests.  Totalling to 32.09.  Typically, a traits page should take 8.79s.  The difference: (- 37.9 32.09) = 5.8s; which explains the slowness:
+
+```
+ ncall     tottime    percall  cumtime  percall  filename:lineno(function)
+----------------------------------------------------------------------------
+     7  0.00002618  3.741e-05    32.09    4.585  socket.py:938(getaddrinfo)
+```
+
+* The above is consistent all the analysis I've done across all the profile dumps.
+
+* Testing my theory out:
+
+```
+@app.route("/test-network")
+def test_network():
+    start = time.time()
+    http_url = urljoin(
+            current_app.config["GN_SERVER_URL"],
+            "version"
+        )
+    result =  requests.get(http_url)
+    duration = time.time() - start
+    app.logger.error(f"{http_url}: {duration:.4f}s")
+
+    start = time.time()
+    local_url = "http://localhost:9093/api/version"
+    result =  requests.get(local_url)
+    duration = time.time() - start
+    app.logger.error(f"{local_url}: {duration:.4f}s")
+    return result.json()
+```
+
+* Results:
+
+```
+2025-07-24 10:20:43 [2025-07-24 10:20:43 +0000] [101] [ERROR] https://cd.genenetwork.org/api3/version: 8.1647s
+2025-07-24 10:20:43 ERROR:gn2.wqflask:https://cd.genenetwork.org/api3/version: 8.1647s
+2025-07-24 10:20:43 [2025-07-24 10:20:43 +0000] [101] [ERROR] result: 1.0
+2025-07-24 10:20:43 ERROR:gn2.wqflask:result: 1.0
+2025-07-24 10:20:43 [2025-07-24 10:20:43 +0000] [101] [ERROR] http://localhost:9093/api/version: 0.0088s
+2025-07-24 10:20:43 ERROR:gn2.wqflask:http://localhost:9093/api/version: 0.0088s
+2025-07-24 10:20:43 [2025-07-24 10:20:43 +0000] [101] [ERROR] result: 1.0
+```
+
+## Possible Mitigations
+
+* Switch over gn-auth.genenetwork.org to localhost.
diff --git a/issues/CI-CD/configurations.gmi b/issues/CI-CD/configurations.gmi
index 54cea47..acd2512 100644
--- a/issues/CI-CD/configurations.gmi
+++ b/issues/CI-CD/configurations.gmi
@@ -4,7 +4,7 @@
 
 * assigned: aruni, fredm
 * priority: normal
-* status: open
+* status: closed, completed
 * keywords: CI, CD, configuration, config
 * type: bug
 
@@ -38,3 +38,7 @@ and at least one of the values other than "localhost" is used to determine the c
 The secrets (e.g. SECRET_KEY, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, etc) can be encrypted and stored in some secrets management system (e.g. Pass [https://www.passwordstore.org/] etc.) setup in each relevant host: better yet, have all configurations (secret or otherwise) encrypted and stored in such a secrets management system and fetch them from there. This reduces the mental overhead of dealing with multiple places to fetch the configs.
 
 From these, the CI/CD system can them build and intern the configurations into the store with guix functions like "plain-file", "local-file", etc.
+
+## Notes
+
+This idea was mostly rejected — it seems — in favour of using external settings files that are shared with the running container and separate build scripts for the different environments. This mostly covers all the bases necessary to get the settings correct.
diff --git a/issues/CI-CD/development-container-checklist.gmi b/issues/CI-CD/development-container-checklist.gmi
new file mode 100644
index 0000000..7cf4687
--- /dev/null
+++ b/issues/CI-CD/development-container-checklist.gmi
@@ -0,0 +1,101 @@
+# Deploying GeneNetwork CD
+
+## Prerequisites
+
+Ensure you have `fzf' installed and Guix is set up with your preferred channel configuration. 
+
+
+## Step 1: Pull the Latest Profiles
+
+```
+guix pull -C channels.scm -p ~/.guix-extra-profiles/gn-machines --allow-downgrades
+guix pull -C channels.scm -p ~/.guix-extra-profiles/gn-machines-shepherd-upgrade --allow-downgrades
+```
+
+
+## Step 2: Source the Correct Profile
+
+```
+. ,choose-profile
+```
+
+
+### Contents of `,choose-profile'
+
+This script lets you interactively select a profile using `fzf': 
+
+```
+#!/bin/env sh
+
+export GUIX_PROFILE="$(guix package --list-profiles | fzf --multi)"
+. "$GUIX_PROFILE/etc/profile"
+
+hash guix
+
+echo "Currently using: $GUIX_PROFILE"
+```
+
+
+## Step 3: Verify the Profile
+
+```
+guix describe
+```
+
+
+## Step 4: Pull the Latest Code
+
+```
+cd gn-machines
+git pull
+```
+
+
+## Step 5: Run the Deployment Script
+
+```
+./genenetwork-development-deploy.sh
+```
+
+
+## Step 6: Restart the Development Container
+
+```
+sudo systemctl restart genenetwork-development-container
+```
+
+
+## Step 7: Verify Changes
+
+Manually confirm that the intended changes were applied correctly. 
+
+
+# Accessing the Development Container on tux02
+
+To enter the running container shell, ensure you're using the *parent* PID of the `shepherd' process. 
+
+
+## Step 1: Identify the Correct PID
+
+Use this command to locate the correct container parent process: 
+
+```
+ps -u root -f --forest | grep -A4 '/usr/local/bin/genenetwork-development-container' | grep shepherd
+```
+
+
+## Step 2: Enter the Container
+
+Replace `46804' with your actual parent PID: 
+
+```
+sudo /home/bonfacem/.config/guix/current/bin/guix container exec 46804 \
+  /gnu/store/m6c5hgqg569mbcjjbp8l8m7q82ascpdl-bash-5.1.16/bin/bash \
+  --init-file /home/bonfacem/.guix-profile/etc/profile --login
+```
+
+
+## Notes
+
+* Ensure the PID is the container’s *shepherd parent*, not a child process. 
+* Always double-check your environment and profiles before deploying. 
diff --git a/issues/CI-CD/failing-services-startup.gmi b/issues/CI-CD/failing-services-startup.gmi
new file mode 100644
index 0000000..751e61c
--- /dev/null
+++ b/issues/CI-CD/failing-services-startup.gmi
@@ -0,0 +1,236 @@
+# Failing Services' Startup
+
+## Tags
+
+* type: bug
+* status: closed, completed
+* priority: high
+* assigned: fredm, bonfacem
+* interested: pjotrp, bonfacem, aruni
+* keywords: deployment, CI, CD
+
+## Description
+
+Upgrading guix to `34453b97005ff86355399df89c8827c57839d9c7` for CI/CD fails with:
+
+```
+2025-08-20 16:05:20 Backtrace:
+2025-08-20 16:05:20            6 (primitive-load "/gnu/store/xbxd2zihw9dssrhips925gri0yn?")
+2025-08-20 16:05:20 In ice-9/eval.scm:
+2025-08-20 16:05:20    191:35  5 (_ _)
+2025-08-20 16:05:20 In gnu/build/linux-container.scm:
+2025-08-20 16:05:20     368:8  4 (call-with-temporary-directory #<procedure 7f014aa3a3f0?>)
+2025-08-20 16:05:20    476:16  3 (_ "/tmp/guix-directory.VWRNbv")
+2025-08-20 16:05:20      62:6  2 (call-with-clean-exit #<procedure 7f014aa1de80 at gnu/b?>)
+2025-08-20 16:05:20    321:20  1 (_)
+2025-08-20 16:05:20 In guix/build/syscalls.scm:
+2025-08-20 16:05:20   1231:10  0 (_ 268566528)
+2025-08-20 16:05:20 
+2025-08-20 16:05:20 guix/build/syscalls.scm:1231:10: In procedure unshare: 268566528: Invalid argument
+2025-08-20 16:05:20 Backtrace:
+2025-08-20 16:05:20            4 (primitive-load "/gnu/store/xbxd2zihw9dssrhips925gri0yn?")
+2025-08-20 16:05:20 In ice-9/eval.scm:
+2025-08-20 16:05:20    191:35  3 (_ #f)
+2025-08-20 16:05:20 In gnu/build/linux-container.scm:
+2025-08-20 16:05:20     368:8  2 (call-with-temporary-directory #<procedure 7f014aa3a3f0?>)
+2025-08-20 16:05:20     485:7  1 (_ "/tmp/guix-directory.VWRNbv")
+2025-08-20 16:05:20 In unknown file:
+2025-08-20 16:05:20            0 (waitpid #f #<undefined>)
+2025-08-20 16:05:20 
+2025-08-20 16:05:20 ERROR: In procedure waitpid:
+2025-08-20 16:05:20 Wrong type (expecting exact integer): #f
+```
+
+Failing services:
+
+* genenetwork3: consistently
+* genenetwork2: consistently
+* gn-auth: intermittently
+
+## Troubleshooting Notes
+
+### Unable to run genenetwork2 in a shell container with the "-C" flag
+
+With the following channels:
+
+```
+$ guix describe
+Generation 3    Aug 28 2025 03:56:44    (current)
+  gn-bioinformatics cffafde
+    repository URL: file:///home/bonfacem/guix-bioinformatics/
+    branch: master
+    commit: cffafde125f3e711418d3ebb62eacd48a3efa8cf
+  guix-forge 3c8dc85
+    repository URL: https://git.genenetwork.org/guix-forge/
+    branch: main
+    commit: 3c8dc85a584c98bc90088ec1c85933d4d10e7383
+  guix-past b14d7f9
+    repository URL: https://codeberg.org/guix-science/guix-past
+    branch: master
+    commit: b14d7f997ae8eec788a7c16a7252460cba3aaef8
+  guix 34453b9
+    repository URL: https://codeberg.org/guix/guix
+    branch: master
+    commit: 34453b97005ff86355399df89c8827c57839d9c7
+```
+
+Running:
+
+```
+$ guix shell -C genenetwork2
+```
+
+Produces:
+
+```
+guix shell: error: unshare: 268566528: Invalid argument
+Backtrace:
+          16 (primitive-load "/export3/local/home/bonfacem/.guix-ext…")
+In guix/ui.scm:
+   2399:7 15 (run-guix . _)
+  2362:10 14 (run-guix-command _ . _)
+In ice-9/boot-9.scm:
+  1752:10 13 (with-exception-handler _ _ #:unwind? _ # _)
+In guix/status.scm:
+    842:4 12 (call-with-status-report _ _)
+In guix/store.scm:
+    703:3 11 (_)
+In ice-9/boot-9.scm:
+  1752:10 10 (with-exception-handler _ _ #:unwind? _ # _)
+In guix/store.scm:
+   690:37  9 (thunk)
+   1331:8  8 (call-with-build-handler _ _)
+   1331:8  7 (call-with-build-handler #<procedure 7fc86bb50de0 at g…> …)
+In guix/scripts/environment.scm:
+  1205:11  6 (proc _)
+In guix/store.scm:
+  2212:25  5 (run-with-store #<store-connection 256.100 7fc87a46d820> …)
+In guix/scripts/environment.scm:
+    911:8  4 (_ _)
+In gnu/build/linux-container.scm:
+    485:7  3 (call-with-container _ _ #:namespaces _ #:host-uids _ # …)
+In unknown file:
+           2 (waitpid #f #<undefined>)
+In ice-9/boot-9.scm:
+  1685:16  1 (raise-exception _ #:continuable? _)
+  1685:16  0 (raise-exception _ #:continuable? _)
+
+ice-9/boot-9.scm:1685:16: In procedure raise-exception:
+Wrong type (expecting exact integer): #f
+```
+
+This is fixed by increasing the value of respawn-delay (default is 0.5s) to 5s.
+
+
+### Unable to write to a temporary directory and issues with running git inside the g-exp
+
+Stack trace:
+```
+2025-09-03 12:23:32 In ice-9/eval.scm:
+2025-09-03 12:23:32    191:35  3 (_ #f)
+2025-09-03 12:23:32 In gnu/build/linux-container.scm:
+2025-09-03 12:23:32     368:8  2 (call-with-temporary-directory #<procedure 7f012241d3f0?>)
+2025-09-03 12:23:32     485:7  1 (_ "/tmp/guix-directory.Bl6jtx")
+2025-09-03 12:23:32 In unknown file:
+2025-09-03 12:23:32            0 (waitpid #f #<undefined>)
+2025-09-03 12:23:32
+
+```
+
+Cryptic message.   Running the g-exps as a program shows:
+
+```
+Receiving objects: 100% (698/698), 16.18 MiB | 30.29 MiB/s, done.
+Resolving deltas: 100% (49/49), done.
+==================================================
+error: cannot run less: No such file or directory
+fatal: unable to execute pager 'less'
+Backtrace:
+           5 (primitive-load "/gnu/store/c9bvy90s5mglp6xdfkc1s4qkzj8?")
+In ice-9/eval.scm:
+    619:8  4 (_ #f)
+In ice-9/boot-9.scm:
+    142:2  3 (dynamic-wind #<procedure 7fa954b25880 at ice-9/eval.s?> ?)
+    142:2  2 (dynamic-wind #<procedure 7fa94b7970c0 at ice-9/eval.s?> ?)
+In ice-9/eval.scm:
+    619:8  1 (_ #(#(#<directory (guile-user) 7fa954b03c80>)))
+In guix/build/utils.scm:
+    822:6  0 (invoke "git" "log" "--max-count" "1")
+
+guix/build/utils.scm:822:6: In procedure invoke:
+ERROR:
+  1. &invoke-error:
+      program: "git"
+      arguments: ("log" "--max-count" "1")
+      exit-status: 128
+      term-signal: #f
+      stop-signal: #f
+```
+
+Fixed by adding "less" to the with-packages form and setting:
+
+```
+(setenv "TERM" "xterm-256color")
+
+```
+
+### gn-auth: sqlite3.OperationalError: unable to open database file
+
+Despite having all file perms correctly set with 0644, we see:
+
+```
+Traceback (most recent call last):
+  File "/gnu/store/ag1m9bv22iwm3sq87xly35y138l6kzd7-profile/lib/python3.11/site-packages/flask/app.py", line 917, in full_dispatch_request
+    rv = self.dispatch_request()
+         ^^^^^^^^^^^^^^^^^^^^^^^
+  File "/gnu/store/ag1m9bv22iwm3sq87xly35y138l6kzd7-profile/lib/python3.11/site-packages/flask/app.py", line 902, in dispatch_request
+    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
+           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  File "/export/data/repositories/gn-auth/gn_auth/auth/authentication/oauth2/views.py", line 102, in authorise
+    return with_db_connection(__authorise__)
+           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  File "/export/data/repositories/gn-auth/gn_auth/auth/db/sqlite3.py", line 63, in with_db_connection
+    return func(conn)
+           ^^^^^^^^^^
+  File "/export/data/repositories/gn-auth/gn_auth/auth/authentication/oauth2/views.py", line 90, in __authorise__
+    return server.create_authorization_response(request=request, grant_user=user)
+           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  File "/gnu/store/ag1m9bv22iwm3sq87xly35y138l6kzd7-profile/lib/python3.11/site-packages/authlib/oauth2/rfc6749/authorization_server.py", line 297, in create_authorization_response
+    args = grant.create_authorization_response(redirect_uri, grant_user)
+           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  File "/export/data/repositories/gn-auth/gn_auth/auth/authentication/oauth2/grants/authorisation_code_grant.py", line 31, in create_authorization_response
+    response = super().create_authorization_response(
+               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  File "/gnu/store/ag1m9bv22iwm3sq87xly35y138l6kzd7-profile/lib/python3.11/site-packages/authlib/oauth2/rfc6749/grants/authorization_code.py", line 158, in create_authorization_response
+    self.save_authorization_code(code, self.request)
+  File "/export/data/repositories/gn-auth/gn_auth/auth/authentication/oauth2/grants/authorisation_code_grant.py", line 45, in save_authorization_code
+    return __save_authorization_code__(
+           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  File "/export/data/repositories/gn-auth/gn_auth/auth/authentication/oauth2/grants/authorisation_code_grant.py", line 106, in __save_authorization_code__
+    return with_db_connection(lambda conn: save_authorisation_code(conn, code))
+           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  File "/export/data/repositories/gn-auth/gn_auth/auth/db/sqlite3.py", line 63, in with_db_connection
+    return func(conn)
+           ^^^^^^^^^^
+  File "/export/data/repositories/gn-auth/gn_auth/auth/authentication/oauth2/grants/authorisation_code_grant.py", line 106, in <lambda>
+    return with_db_connection(lambda conn: save_authorisation_code(conn, code))
+                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  File "/export/data/repositories/gn-auth/gn_auth/auth/authentication/oauth2/models/authorization_code.py", line 92, in save_authorisation_code
+    cursor.execute(
+sqlite3.OperationalError: unable to open database file
+```
+
+Fixed above by correctly mapping:
+
+```
+-                                                (source auth-db-path)
++                                                (source (dirname auth-db-path))
+```
+
+in the relevant g-exp, and making sure that the parent directory is set to #o775 (rwx for both user/group).
+
+## Also See
+
+=> https://issues.guix.gnu.org/78356 Broken system and home containers
+=> https://codeberg.org/guix/guix/src/commit/34453b97005ff86355399df89c8827c57839d9c7/guix/build/syscalls.scm#L1218-L1233 How "unshare" is defined
+=> https://codeberg.org/guix/guix/src/commit/34453b97005ff86355399df89c8827c57839d9c7/gnu/build/linux-container.scm#L321 Where `unshare` is called
diff --git a/issues/CI-CD/profiling-flask.gmi b/issues/CI-CD/profiling-flask.gmi
new file mode 100644
index 0000000..2d0c539
--- /dev/null
+++ b/issues/CI-CD/profiling-flask.gmi
@@ -0,0 +1,33 @@
+# Profiling GN
+
+Use this simple structure:
+
+```
+from werkzeug.middleware.profiler import ProfilerMiddleware
+
+
+app = Flask(__name__)
+app.config["PROFILE"] = True
+app.wsgi_app = ProfilerMiddleware(
+    app.wsgi_app,
+    restrictions=[40, "main"],
+    profile_dir="profiler_dump",
+    filename_format="{time:.0f}-{method}-{path}-{elapsed:.0f}ms.prof",
+)
+```
+
+
+You can use gprof2dot to visualise the profile
+
+```
+guix shell gprof2dot -- gprof2dot -f pstats 1753202013-GET-show_trait-37931ms.prof > 1753202013-GET-show_trait-37931ms.prof.dot
+guix shell xdot -- xdot 1753202013-GET-show_trait-37931ms.prof.dot
+```
+
+Or snakeviz to visualize it:
+
+
+```
+scp genenetwork:/home/bonfacem/profiling/1753202013-GET-show_trait-37931ms.prof /tmp/test
+snakeviz 1753202013-GET-show_trait-37931ms.prof
+```
diff --git a/issues/CI-CD/troubleshooting-within-the-development-container.gmi b/issues/CI-CD/troubleshooting-within-the-development-container.gmi
new file mode 100644
index 0000000..3aa8c3b
--- /dev/null
+++ b/issues/CI-CD/troubleshooting-within-the-development-container.gmi
@@ -0,0 +1,46 @@
+# Troubleshooting inside the GN dev container
+* type: systems, debugging, container
+* keywords: container, troubleshooting, logs, webhooks
+
+You need to find the development container so that you can begin troubleshooting:
+
+```
+ps -u root -f --forest | grep -A4 '/usr/local/bin/genenetwork-development-container' | grep shepherd
+```
+
+Example output:
+
+```
+root      16182  16162  0 03:57 ?        00:00:04  \_ /gnu/store/n87px1cazqkav83npg80ccp1n777j08s-guile-3.0.9/bin/guile --no-auto-compile /gnu/store/b4n5ax7l1ccia7sr123fqcjqi4vy03pv-shepherd-1.0.2/bin/shepherd --config /gnu/store/5ahb3745wlpa5mjsbk8j6frn78khvzzw-shepherd.conf
+```
+
+Get into the container:
+
+```
+# Use the correct pid and guix/bash path.
+
+sudo /home/bonfacem/.config/guix/current/bin/guix container exec 16182 /gnu/store/m6c5hgqg569mbcjjbp8l8m7q82ascpdl-bash-5.1.16/bin/bash --init-file /home/bonfacem/.guix-profile/etc/profile --login
+```
+
+All the gn related logs can be found in "/var/log/cd":
+
+```
+genenetwork2.log
+genenetwork3.log
+gn-auth.log
+gn-guile.log
+```
+
+All the nginx log are in "/var/log/nginx"
+
+Sometimes, it's useful to trigger webhooks while troubleshooting.  Here are all the relevant webhooks:
+
+```
+/gn-guile
+/genenetwork2
+/genenetwork3
+/gn-libs
+/gn-auth
+```
+
+Inside the container, we have "coreutils-minimal", and "curl" that you can use to troubleshoot.