Skip to content

Conversation

@carlosthe19916
Copy link
Contributor

@carlosthe19916 carlosthe19916 commented Nov 7, 2025

Devcontainers is kinda a standard way of setting up development environments so we guarantee a solid, reliable, and automated way of setting up dependencies.

This PR adds Devcontainers and includes:

  • Install OS minimal requirements like libssl-dev and postgres-client
  • Install Rust
  • Install minimal VSCode extensions for start developing with Rust apps
  • Setup a Postgresql database and Keycloak
    • The environment variables are preconfigured so executing cargo run --bin trustd api should be all you need.

This PR also includes a video demo under the directory .devcontainer/assets/demo.mp4

Note: I have encounter an issue with executing AUTH_DISABLED=true cargo run --bin trustd which enables the Postgresql database in from the filesystem: error=Connection Error: pool timed out while waiting for an open connection: pool timed out while waiting for an open connection: pool timed out while waiting for an open connection database=Database I ignore the reason but I believe having the database in a container as described by the docker-compose.yaml included in this PR should be a better way of representing a real environment

EDIT: As an additional note, this should allow users to run Codespaces from Github. There are other tools around Devcontainers like DevPod among others. So I hope this could help new comers to this repo to quickly setup their environments and start playing with the code

image

Summary by Sourcery

Set up a reproducible development environment using Devcontainers, including automated provisioning of OS dependencies, Postgres database, and Keycloak authentication service

New Features:

  • Add devcontainers configuration (Dockerfile, devcontainer.json, and docker-compose) to provision a development environment with Rust, Postgres, and Keycloak

Enhancements:

  • Provide Keycloak initialization and wait scripts to automate realm, role, client, and user setup
  • Add post-create and initialize command scripts to configure shell aliases and container startup

Documentation:

  • Add README with instructions for using Devcontainers with Docker and Podman

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 7, 2025

Reviewer's Guide

This PR sets up a fully automated Devcontainer environment by adding a base Dockerfile and devcontainer.json, orchestrating Trustify, Postgres and Keycloak services via docker-compose, providing init and readiness scripts for Keycloak, and including container lifecycle hooks and developer documentation.

Sequence diagram for Devcontainer startup and service initialization

sequenceDiagram
  participant Devcontainer
  participant "Keycloak Service"
  participant "Keycloak Wait Script"
  participant "Keycloak Init Script"
  participant "Postgres DB"
  participant "Trustify Service"

  Devcontainer->>"Keycloak Service": Start Keycloak container
  "Keycloak Service"->>"Keycloak Wait Script": Signal ready when HTTP available
  "Keycloak Wait Script"->>"Keycloak Init Script": On ready, run initialization
  "Keycloak Init Script"->>"Keycloak Service": Configure realm, roles, users, clients
  Devcontainer->>"Postgres DB": Start Postgres container
  Devcontainer->>"Trustify Service": Start Trustify container
  "Trustify Service"->>"Postgres DB": Connect for DB access
  "Trustify Service"->>"Keycloak Service": Connect for OIDC authentication
Loading

Flow diagram for Keycloak initialization process

flowchart TD
  start["Start Keycloak container"] --> wait["Run kc-wait.sh (wait for HTTP)"]
  wait --> init["Run kc-init.sh (initialize realm)"]
  init --> createRealm["Create 'trustd' realm"]
  createRealm --> createRole["Create 'admin' role"]
  createRole --> createScopes["Create document scopes"]
  createScopes --> mapScopes["Map scopes to role"]
  mapScopes --> createUser["Create 'admin' user"]
  createUser --> setPassword["Set password for user"]
  setPassword --> assignRole["Assign 'admin' role to user"]
  assignRole --> createClients["Create 'ui' and 'cli' clients"]
  createClients --> assignRoleServiceAccount["Assign 'admin' role to cli service account"]
  assignRoleServiceAccount --> done["Keycloak ready"]
Loading

File-Level Changes

Change Details Files
Add base Devcontainer environment
  • Use Ubuntu-based devcontainer image and install build essentials, libssl-dev, and PostgreSQL client
  • Configure devcontainer.json to define build context, forwarded ports, environment variables, and VSCode extensions
.devcontainer/Dockerfile
.devcontainer/devcontainer.json
Orchestrate services with docker-compose
  • Define trustify service with custom image build, environment variables, ports, and workspace volume
  • Add PostgreSQL service with persistent volume and credentials
  • Set up Keycloak service and link it with init and wait helper containers
.devcontainer/docker-compose.yml
Provide Keycloak initialization and readiness scripts
  • Implement kc-wait.sh to poll Keycloak until it becomes available
  • Create kc-init.sh to bootstrap realm, roles, scopes, clients, and users
.devcontainer/keycloak/kc-wait.sh
.devcontainer/keycloak/kc-init.sh
Add container lifecycle hooks and documentation
  • postCreateCommand.sh injects shell aliases for migrating DB, running API, and connecting via psql
  • initializeCommand.sh logs the Devcontainer ID before launch
  • README.md explains Docker/Podman setup and VSCode Devcontainer usage
.devcontainer/postCreateCommand.sh
.devcontainer/initializeCommand.sh
.devcontainer/README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `.devcontainer/keycloak/kc-init.sh:40` </location>
<code_context>
+/opt/keycloak/bin/kcadm.sh create users -r ${TRUSTIFY_REALM} -s username=${TRUSTIFY_USERNAME} -s enabled=true -s firstName="admin" -s lastName="admin" -s email="[email protected]" -o
+/opt/keycloak/bin/kcadm.sh set-password -r ${TRUSTIFY_REALM} --username admin --new-password admin
+
+/opt/keycloak/bin/kcadm.sh add-roles -r ${TRUSTIFY_REALM} --uusername ${TRUSTIFY_USERNAME} --rolename ${TRUSTIFY_ROLE}
+
+# Clients
</code_context>

<issue_to_address>
**issue (typo):** Possible typo in kcadm.sh argument '--uusername'.

Please update '--uusername' to '--username' to ensure correct role assignment.

```suggestion
/opt/keycloak/bin/kcadm.sh add-roles -r ${TRUSTIFY_REALM} --username ${TRUSTIFY_USERNAME} --rolename ${TRUSTIFY_ROLE}
```
</issue_to_address>

### Comment 2
<location> `.devcontainer/Dockerfile:3-4` </location>
<code_context>
+FROM mcr.microsoft.com/devcontainers/base:ubuntu
+
+RUN sudo apt update && \
+    sudo apt install -y build-essential pkg-config libssl-dev postgresql-client
</code_context>

<issue_to_address>
**suggestion:** Using 'sudo' in Dockerfile may be unnecessary.

Since Dockerfile commands are executed as root by default, 'sudo' can be removed to streamline the build and prevent complications if the user context changes in the base image.
</issue_to_address>

### Comment 3
<location> `.devcontainer/README.md:27` </location>
<code_context>
+
+Install the extension https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
+
+Only if you use podman, thefore Optional:
+
+Go to the Extension Settings:
</code_context>

<issue_to_address>
**issue (typo):** Typo: 'thefore' should be 'therefore'.

Change 'thefore' to 'therefore' to improve readability.

```suggestion
Only if you use podman, therefore Optional:
```
</issue_to_address>

### Comment 4
<location> `.devcontainer/README.md:35` </location>
<code_context>
+- `Dev › Containers: Docker Path` set `podman`
+- `Dev › Containers: Docker Socket Path` set `/run/podman/podman.sock`
+
+To open the repository with DevContainers do `Ctrl + Shift + P` and enter `Dev Containers: Rebuild and Reopen in Container` or `Dev Containers: Reopen in Container`. For more options see the Extension documentations.
</code_context>

<issue_to_address>
**suggestion (typo):** Use 'documentation' instead of 'documentations'.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

/opt/keycloak/bin/kcadm.sh create users -r ${TRUSTIFY_REALM} -s username=${TRUSTIFY_USERNAME} -s enabled=true -s firstName="admin" -s lastName="admin" -s email="[email protected]" -o
/opt/keycloak/bin/kcadm.sh set-password -r ${TRUSTIFY_REALM} --username admin --new-password admin

/opt/keycloak/bin/kcadm.sh add-roles -r ${TRUSTIFY_REALM} --uusername ${TRUSTIFY_USERNAME} --rolename ${TRUSTIFY_ROLE}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (typo): Possible typo in kcadm.sh argument '--uusername'.

Please update '--uusername' to '--username' to ensure correct role assignment.

Suggested change
/opt/keycloak/bin/kcadm.sh add-roles -r ${TRUSTIFY_REALM} --uusername ${TRUSTIFY_USERNAME} --rolename ${TRUSTIFY_ROLE}
/opt/keycloak/bin/kcadm.sh add-roles -r ${TRUSTIFY_REALM} --username ${TRUSTIFY_USERNAME} --rolename ${TRUSTIFY_ROLE}

Comment on lines +3 to +4
RUN sudo apt update && \
sudo apt install -y build-essential pkg-config libssl-dev postgresql-client
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Using 'sudo' in Dockerfile may be unnecessary.

Since Dockerfile commands are executed as root by default, 'sudo' can be removed to streamline the build and prevent complications if the user context changes in the base image.

@ctron
Copy link
Contributor

ctron commented Nov 7, 2025

I like the idea. To make things easier, I don't think you need either keycloak or postgres. You can use the embedded OIDC issuer and the embedded postgres database. Former should be active by default when using --feature pm.

Signed-off-by: Carlos Feria <[email protected]>
@codecov
Copy link

codecov bot commented Nov 7, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.17%. Comparing base (2381bef) to head (082acbe).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2096      +/-   ##
==========================================
+ Coverage   68.03%   68.17%   +0.14%     
==========================================
  Files         367      368       +1     
  Lines       20590    20682      +92     
  Branches    20590    20682      +92     
==========================================
+ Hits        14008    14100      +92     
+ Misses       5746     5741       -5     
- Partials      836      841       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@carlosthe19916
Copy link
Contributor Author

I like the idea. To make things easier, I don't think you need either keycloak or postgres. You can use the embedded OIDC issuer and the embedded postgres database. Former should be active by default when using --feature pm.

@ctron

Although I do see the value in the embedded OIDC, In my daily routine I do rely in tools like Keycloak. When it comes to integration with other tools like the UI having something like Keycloak that allows me to go deep in configuration is very important.

What about having both? I believe Devcontainer allow the definition of multiple setups that can coexist together.

  • minimal: that should rely on the embedded postgresql and oidc
  • full: that relies on keycloak and postgres as containers

This way we both have what we need. What do you think? Does it seems like a fair compromise for both types of users?

@carlosthe19916
Copy link
Contributor Author

I added a commit that add both, the required minimal Devcontainer and also a full one. Now when users want to setup their development environment they will be asked which one they want:

image

Copy link
Contributor

@ctron ctron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of having both. Thanks for that.

I just tried it out, but it doesn't seem to work. At least for me. Working on a mac today, I had to switch VScode dev container to podman first. Then it starts, but I can't connect to the frontend. I says "connection refused" in the logs.

@carlosthe19916
Copy link
Contributor Author

@ctron thanks for the review... I'll be out for 1 week but I'll look into it as soon as I am back.

@carlosthe19916
Copy link
Contributor Author

@ctron I have done an additional test to the trustify-minimal devcontainer configuration using Podman and I did not see errors.

  • I did see a cache issue in my browser so I needed to do "Ctrl + Shift + R to refresh" the page and clean cache. That is also seen in the video attached below. But that is a browser issue not a devcontainer thing.
  • "I says "connection refused" in the logs." was it the log of the browser, log of the backend? Could you please share more info on that to diagnose it as I could not reproduce it.

Note: devcontainers map ports to the host machine, in the case of the trustify-minimal devcontainer config the ports are mapped as:

  • 8080: mapped to any available port in the host
  • 8090: needs to be mapped to the same port in the host. If the port is not available VSCode will thrown a warning message.

Maybe your port 8080 was mapped to a different port in your host machine therefore you were not able to open http://localhost:8080 ?

Screenshot From 2025-11-18 10-01-09
Screencast.From.2025-11-18.10-03-27.mp4

@ctron
Copy link
Contributor

ctron commented Nov 18, 2025

So I did the following:

  • Start podman
  • Start vscode, open project
  • Click on ports
  • Click on "8080"

What I can see is:

  • Devcontainers seems running:
    ➜  trustify git:(feat/devcontainers) ✗ podman ps
    CONTAINER ID  IMAGE                                           COMMAND               CREATED     STATUS        PORTS       NAMES
    0af95e44a2b1  localhost/devcontainer-trustify-minimal:latest  /bin/sh -c while ...  8 days ago  Up 2 minutes              minimal-trustify-minimal-1
    
  • Browser opens, but keeps connecting

I am not aware of anything else running on port 8080. I'd assume I'd see a page loading in that case.

@carlosthe19916
Copy link
Contributor Author

@ctron Devcontainers and Vscode map the container port to the host and it does not necessarily use the same port in the container and in the host. Likely your 8080 port is not being mapped to 8080 in your host OS. That is how it works devcontainers. Most of the time it will map the same ports in the host and in the container but sometimes it won't.

In the image below, the 8080 port has been mapped to 8081 in my host OS. So if I open http://localhost:8081 it will work.
May I ask you to double-check the Ports tab inside the VSCode IDE? just to discard there is an error mapping ports.

Screenshot From 2025-11-18 10-58-35 Screenshot From 2025-11-18 10-57-13

@ctron
Copy link
Contributor

ctron commented Nov 19, 2025

Here is what I see:
image

Listening on port 8080 is only VScode:

Code\x20H 3410       jreimann   31u  IPv4 0x264f126e1c5caefe      0t0    TCP localhost:8080 (LISTEN)
Code\x20H 3410       jreimann   35u  IPv4 0x6a18c4f22b050c37      0t0    TCP localhost:8090 (LISTEN)
Code\x20H 3410       jreimann   36u  IPv4  0xf26c645d45e0baf      0t0    TCP localhost:9010 (LISTEN)

Exiting VScode, those listening sockets are gone.

@carlosthe19916
Copy link
Contributor Author

@ctron
Could you confirm whether AUTH_DISABLED=true cargo run --bin trustd works? Notice we are disabling AUTH

I have tested it in a 100% clean OS and I did find issues with forwarding the container port that belongs to the embedded oidc. I made it work making this change in the source code:

Before:

server
.base(base)
.port(port)
.add_issuer(name.to_string(), issuer)?;

After:

    server
        .base(base)
        .port(port)
        .bind(std::net::IpAddr::V6(Ipv6Addr::UNSPECIFIED))
        .add_issuer(name.to_string(), issuer)?;

The problem being that the embedded oidc exposes its service through http://[::1] hence not allowing mapping between the container and the OS.

Not sure if that is the problem you are facing though.


### Podman

Start Podman service for a regular user (rootless) and make it listen to a socket:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be scoped to "Linux", it works differently on Windows and MacOS, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Windows and MacOS have to use "Podman Machine" if am not wrong.
I have no MacOS neither Windows for me to be able to write accurate instructions. I expect the README to evolve and be enhanced title by title by Windows and MacOS users if they find DevContainer within VSCode useful.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm against having half-done instructions. If we can't come up with a solution which works on all platforms, including documentation, then it might better to not do it. Maybe someone with more Mac OS/Windows experience can amend this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this PR as a well intended contribution to a community project.

If we could merge this PR it would help me a lot as it will allow me to save a ton of time as a regular code watcher of this repository.

I guess the majority of contributors of this repository are Windows and MacOS users and very few of them use Linux.

It is not my intention to make the core contributors harder. Unfortunately I have no way of testing things on MacOS nor Windows and be sure that the instructions are accurate.

I was expecting an "evolution" approach, evolve documentation in the same peace as users start using it. There is low risk as it does not affect the code in any way. But if the approach "all or nothing" is the approach advised by the core contributors of this project then I am afraid I cannot anything about it so please feel free to close this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a side note. This PR added a README for setting up Devcontainers with good intentions, but it brought more troubles than expected so maybe it is just better to delete the README.md inside the .devcontainer directory. Documenting how to set up podman or docker is something out of the scope of any project.

Here are some examples of relatively big projects that use devcontainers. None of them have docs for setting up Podman/Docker:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess […] Unfortunately I have no way of testing things on MacOS nor Windows and be sure that the instructions are accurate.

I understand, but then I don't want to merge this. If we end up with instructions that only work for part of users, that will cause frustration, because things don't work.

I am sure you can find someone with MacOS and collaborate. What would at least sort out least two out of three.

If that's not possible, then I'm against merging this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants