Skip to content

Conversation

@marshallwp
Copy link

@marshallwp marshallwp commented Jan 28, 2026

Adds a quadlets directory containing quadlet equivalents for the docker-compose.yml file. Additionally, a setup-quadlets.sh script is included that will generate random values as secrets and add them to the user's podman instance. The two are intended to be used together, as the quadlets are configured to use the generated secrets.

They were tested using the rootful placement of /etc/containers/systemd/, but should work in rootless deployments too.

Addresses #803

Summary by CodeRabbit

  • Documentation

    • Added a comprehensive guide for deploying via Podman Quadlets: pod setup, secret handling (newline caveats), symbolic link search paths, auto-update options (manual/scheduled) and usage steps.
  • New Features

    • Podman-based deployment including the app, managed PostgreSQL and Redis services, port exposure, and optional automatic image updates with health checks and persistent storage.
  • Chores

    • Added Quadlet manifests and a setup workflow to create/manage secrets, persistent volumes, and service lifecycle.

This should make it clearer to users what
this directory contains and whether it is
something of interest to them.
It was from a more advanced script that also managed instantiation of quadlets.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 28, 2026

Walkthrough

Adds Podman Quadlets for Sourcebot: pod and container manifests for Sourcebot, PostgreSQL, and Redis; a POSIX shell setup script to generate and register Podman secrets (including URL-encoding the DB URL); and README documentation for deployment and secret handling.

Changes

Cohort / File(s) Summary
Pod manifest
quadlets/sourcebot.pod
Adds a Podman pod manifest publishing port 3000:3000 for the Sourcebot pod.
Container manifests
quadlets/sourcebot.container, quadlets/postgres.container, quadlets/redis.container
Adds systemd-quadlet container unit files: Sourcebot (binds config.json, maps multiple secrets to env, depends on postgres/redis, auto-update), PostgreSQL (postgres:17) with persistent volume, secret-based password and pg_isready healthcheck, and Redis (redis:8) with persistent volume and healthcheck.
Secret/setup script
quadlets/setup-quadlets.sh
New POSIX-compatible shell script to create a secrets directory, generate secrets (gpg --dry-run), remove/create Podman secrets, URL-encode the DB password into SOURCEBOT_DATABASE_URL, and exports a url_encode() function.
Documentation
quadlets/README.md
New README describing deployment with Podman Quadlets, Podman 5+ requirement, secret creation caveats (trailing newlines), quadlet placement, usage steps, and Podman AutoUpdate guidance.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Script as "setup-quadlets.sh"
    participant Podman
    participant Systemd
    participant Quadlets as "quadlet files"
    participant Pod as "sourcebot.pod"

    User->>Script: run setup script
    Script->>Script: generate secrets & url-encode DB URL
    Script->>Podman: remove/create secrets (POSTGRES_ADMIN_PASSWORD, SOURCEBOT_*)
    Script-->>User: "Setup complete!"

    User->>Systemd: place quadlets, enable units
    Systemd->>Quadlets: read pod & container manifests
    Systemd->>Podman: create/start pod (publish 3000:3000)
    Systemd->>Podman: start postgres & redis containers (pull, mount volumes, healthchecks)
    Systemd->>Podman: start sourcebot container (bind config, inject secrets)
    Podman->>Pod: inject secrets into containers
    Pod->>Pod: containers run health checks
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(quadlets): add quadlet deployment option' clearly and specifically summarizes the main change—adding Quadlet configuration files for deploying Sourcebot via Podman Quadlets.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@quadlets/setup-quadlets.sh`:
- Line 55: The printf line that builds the DATABASE_URL uses unquoted command
substitution causing word-splitting if the password contains spaces/special
chars; update the invocation so the password read and the url_encode call are
both quoted (i.e., quote the $(cat ./secrets/postgres_admin_password) inside the
url_encode call used in the printf) so the printf and podman secret create
SOURCEBOT_DATABASE_URL receive a single, correctly encoded string; locate the
line containing printf, url_encode, and podman secret create
SOURCEBOT_DATABASE_URL and wrap the inner substitution in quotes to fix the
issue.
- Line 27: The podman secret pipeline is using inconsistent privilege
escalation: 'podman secret ls' runs unprivileged while the removal uses 'sudo
... podman secret rm', which can cause mismatched results; make the privilege
usage consistent by running both listing and removal under the same privilege
level (e.g., prefix the listing with sudo so use 'sudo podman secret ls ... |
sudo xargs --no-run-if-empty podman secret rm') and ensure the same secret name
regex
"(POSTGRES_ADMIN_PASSWORD|SOURCEBOT_AUTH_SECRET|SOURCEBOT_ENCRYPTION_KEY|SOURCEBOT_DATABASE_URL)"
and xargs options remain unchanged.

In `@quadlets/sourcebot.container`:
- Line 14: The volume line "Volume=./config.json:/data/config.json:ro,z" uses a
relative path that may resolve incorrectly when the quadlet is placed in system
dirs; update this to an absolute path to the intended config (e.g.,
/path/to/config.json) or add documentation/comments instructing users to place
config.json in the same quadlet directory and explicitly warn about
relative-path resolution; ensure the updated value replaces the
"Volume=./config.json:/data/config.json:ro,z" entry or add validation/notes so
the container receives the correct config file.
- Line 22: The container quadlet references a required secret named
SOURCEBOT_EE_LICENSE_KEY which is not created by setup-quadlets.sh and will
cause Podman to fail on startup; update setup-quadlets.sh to create a
placeholder secret (SOURCEBOT_EE_LICENSE_KEY) when generating secrets or add a
documented step in your README that instructs users to create the
SOURCEBOT_EE_LICENSE_KEY secret manually before starting the container, ensuring
the secret name matches the quadlet entry so Podman no longer errors with "no
such secret".
🧹 Nitpick comments (5)
quadlets/setup-quadlets.sh (3)

7-7: Replace -a with && for POSIX compliance.

The -a operator within [ ] is not well-defined in POSIX and can behave unexpectedly. Since the shebang specifies /usr/bin/env sh, use portable constructs.

♻️ Suggested fix
-if [ $GENERATE_NEW_SECRETS != 'Y' -a $GENERATE_NEW_SECRETS != 'y' -a $GENERATE_NEW_SECRETS != 'N' -a $GENERATE_NEW_SECRETS != 'n' ]; then
+if [ "$GENERATE_NEW_SECRETS" != 'Y' ] && [ "$GENERATE_NEW_SECRETS" != 'y' ] && [ "$GENERATE_NEW_SECRETS" != 'N' ] && [ "$GENERATE_NEW_SECRETS" != 'n' ]; then

Also note: variables should be quoted to prevent word splitting/globbing issues.


12-12: Replace -o with || for POSIX compliance.

Same issue as above—use || between separate test commands instead of -o within a single [ ].

♻️ Suggested fix
-if [ $GENERATE_NEW_SECRETS = 'Y' -o $GENERATE_NEW_SECRETS = 'y' ]; then
+if [ "$GENERATE_NEW_SECRETS" = 'Y' ] || [ "$GENERATE_NEW_SECRETS" = 'y' ]; then

14-14: mkdir --mode is a GNU extension, not POSIX-portable.

If targeting POSIX sh, consider using mkdir followed by chmod, or simply mkdir -m:

♻️ Suggested fix
-        mkdir --mode='u=rw,g=,o=' './secrets'
+        mkdir -m 0600 './secrets'

Note: -m is more widely supported than --mode.

quadlets/redis.container (1)

5-12: Consider adding Pull=always for consistency with other containers.

The postgres.container specifies Pull=always, but this container does not. For consistent behavior across all services, consider adding the pull policy here as well.

♻️ Suggested addition
 [Container]
 Image=docker.io/library/redis:8
+Pull=always
 HealthCmd=["redis-cli","ping"]
quadlets/README.md (1)

45-45: Convert bare URL to proper Markdown link.

The URL should be formatted as a Markdown link to satisfy linting and improve readability.

♻️ Suggested fix
->
-> *Source: https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html#synopsis*
+>
+> *Source: [Podman systemd.unit documentation](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html#synopsis)*

Also add an example of how to start the pod.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@quadlets/setup-quadlets.sh`:
- Line 14: The mkdir invocation in setup-quadlets.sh uses --mode='u=rw,g=,o='
which omits the execute bit so the './secrets' directory is not traversable;
update the mkdir --mode argument used to create './secrets' (the line with mkdir
--mode='u=rw,g=,o=' './secrets') to include the execute permission for the owner
(e.g., u=rwx or an equivalent numeric mode like 0700) so the owner can enter and
operate inside the directory.
🧹 Nitpick comments (2)
quadlets/setup-quadlets.sh (2)

7-7: Use POSIX-compliant conditionals instead of -a.

The -a operator inside [ ] is not well-defined in POSIX sh and can behave unexpectedly. Use separate tests joined by && for reliable behavior.

♻️ Suggested fix
-if [ $GENERATE_NEW_SECRETS != 'Y' -a $GENERATE_NEW_SECRETS != 'y' -a $GENERATE_NEW_SECRETS != 'N' -a $GENERATE_NEW_SECRETS != 'n' ]; then
+if [ "$GENERATE_NEW_SECRETS" != 'Y' ] && [ "$GENERATE_NEW_SECRETS" != 'y' ] && [ "$GENERATE_NEW_SECRETS" != 'N' ] && [ "$GENERATE_NEW_SECRETS" != 'n' ]; then

12-12: Use POSIX-compliant conditionals instead of -o.

Same issue as line 7—use || between separate tests.

♻️ Suggested fix
-if [ $GENERATE_NEW_SECRETS = 'Y' -o $GENERATE_NEW_SECRETS = 'y' ]; then
+if [ "$GENERATE_NEW_SECRETS" = 'Y' ] || [ "$GENERATE_NEW_SECRETS" = 'y' ]; then

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@quadlets/README.md`:
- Line 4: Update the README sentence to clarify that the auto-update timer is
present with a default midnight schedule but is not enabled by default: replace
the phrase "not scheduled by default" with wording like "the timer exists and is
scheduled to run at midnight by default, but it is not enabled by default; you
can enable or run it manually via `podman auto-update`" so readers understand
the timer's default schedule versus its enabled state.
🧹 Nitpick comments (1)
quadlets/README.md (1)

60-60: Clarify the purpose of keeping the secrets directory.

The phrase "That is used to drop and recreate the secrets without changing them" is confusing. It should explicitly state that keeping the secrets directory allows rerunning the script with GENERATE_NEW_SECRETS='N' to re-register existing secret values.

♻️ Proposed rewording for clarity
-4. Optionally delete the `secrets` subdirectory.  This is more secure, but will prevent rerunning the `setup-quadlets.sh` script with `GENERATE_NEW_SECRETS` set to 'N'. That is used to drop and recreate the secrets without changing them.  Useful if you suspect you've succumbed to the important issue noted above.
+4. Optionally delete the `secrets` subdirectory.  This is more secure, but will prevent rerunning the `setup-quadlets.sh` script with `GENERATE_NEW_SECRETS='N'` to re-register the existing secret values without regenerating them.  Keeping the directory is useful if you need to recreate secrets (e.g., if they were corrupted by the newline issue noted above).

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.

1 participant