Skip to content

(projects) add projects app support - #59

Open
Nastaliss wants to merge 5 commits into
mainfrom
feat/projects
Open

(projects) add projects app support#59
Nastaliss wants to merge 5 commits into
mainfrom
feat/projects

Conversation

@Nastaliss

@Nastaliss Nastaliss commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added Projects application support via CLI and Ansible, including OIDC-enforced authentication, single-container deployment, optional S3 uploads, and optional SMTP configuration; added optional cAdvisor monitoring.
  • Documentation
    • Added Projects guides and a complete role reference for the Projects service.
  • Bug Fixes
    • Updated CLI vars documentation and success messaging to accurately reflect the active secret backend (including OpenBao behavior and when vault.yml is not produced).
  • Chores
    • Made CLI bootstrap “Requirements” prompts app-aware using per-app external dependency declarations; added/expanded end-to-end and unit tests for Projects bootstrapping and OIDC behavior.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds Projects as a standalone Sails.js application supported by st-cli, app metadata, OIDC-based environment rendering, a new Ansible role with optional cAdvisor deployment, tests, and documentation.

Changes

Projects application

Layer / File(s) Summary
App metadata and environment contract
cli/st_cli/core/appmeta.py, cli/st_cli/core/resources/apps/*, cli/st_cli/core/envrender.py, cli/st_cli/core/resources/templates/env/*, cli/tests/test_appmeta.py, cli/tests/test_envrender.py
Adds Projects metadata, per-app infrastructure requirements, OIDC issuer derivation, and conditional dotenv rendering for OIDC, S3, and SMTP settings.
Projects bootstrap and secret backend handling
cli/st_cli/cmd/bootstrap.py, cli/st_cli/core/writer.py, cli/tests/test_bootstrap.py, cli/tests/test_writer.py
Adds the Projects questionnaire, app-aware requirements output, backend-aware vars headers, secret handling, and coverage for provider, storage, email, and deployment paths.
Projects role deployment
roles/projects/*
Adds role defaults, argument specifications, Podman deployment tasks, Projects and cAdvisor Compose templates, and environment rendering.
Documentation and validation
README.md, changelogs/fragments/projects.yml, docs/05-projects/*, roles/projects/REFERENCE.md
Documents Projects deployment, storage, OIDC, rollback, troubleshooting, role arguments, and CLI support.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant st-cli
  participant SecretBackend
  participant AnsibleRole
  participant Podman
  Operator->>st-cli: bootstrap projects <env>
  st-cli->>SecretBackend: store project secrets
  st-cli->>AnsibleRole: write project variables and manifest
  AnsibleRole->>Podman: configure and deploy Projects
  Podman-->>Operator: run Projects container
Loading

Possibly related PRs

Suggested reviewers: zeylos

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding support for the projects app.
Docstring Coverage ✅ Passed Docstring coverage is 93.55% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@changelogs/fragments/projects.yml`:
- Line 2: Update the Projects changelog entry to describe uploads as “optional
S3-backed uploads” instead of “S3-backed uploads,” leaving the rest of the entry
unchanged.

In `@roles/projects/REFERENCE.md`:
- Line 2: Update the documentation in REFERENCE.md to satisfy linting: add
required blank lines around all affected headings, label the playbook code fence
as yaml, and replace “Prometheus compatible” with “Prometheus-compatible” while
preserving the surrounding content.

In `@roles/projects/templates/projects/compose.yaml.j2`:
- Around line 10-13: Update the volumes section in the compose template to
derive upload mounts from the configured st_projects_directories list rather
than hardcoded defaults. Add or use each directory’s container-path metadata and
loop over the entries so custom directories are mounted and an empty list
produces no upload mounts, preserving the documented S3-only behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1d4e0201-2bec-4738-8236-8c59b75fcc3d

📥 Commits

Reviewing files that changed from the base of the PR and between f82a451 and fe1df52.

📒 Files selected for processing (27)
  • README.md
  • changelogs/fragments/projects.yml
  • cli/st_cli/cmd/bootstrap.py
  • cli/st_cli/core/appmeta.py
  • cli/st_cli/core/envrender.py
  • cli/st_cli/core/resources/apps/drive.yml
  • cli/st_cli/core/resources/apps/keycloak.yml
  • cli/st_cli/core/resources/apps/meet.yml
  • cli/st_cli/core/resources/apps/messages.yml
  • cli/st_cli/core/resources/apps/projects.yml
  • cli/st_cli/core/resources/templates/env/projects.env.j2
  • cli/st_cli/core/writer.py
  • cli/tests/test_appmeta.py
  • cli/tests/test_bootstrap.py
  • cli/tests/test_envrender.py
  • cli/tests/test_writer.py
  • docs/05-projects/01-projects.md
  • roles/projects/REFERENCE.md
  • roles/projects/defaults/main.yml
  • roles/projects/meta/argument_specs.yml
  • roles/projects/meta/main.yml
  • roles/projects/tasks/deploy.yml
  • roles/projects/tasks/deploy/projects.yml
  • roles/projects/tasks/main.yml
  • roles/projects/templates/monitoring/compose_cadvisor.yaml.j2
  • roles/projects/templates/projects/compose.yaml.j2
  • roles/projects/templates/projects/env.j2

Comment thread changelogs/fragments/projects.yml Outdated
Comment thread roles/projects/REFERENCE.md
Comment thread roles/projects/templates/projects/compose.yaml.j2

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cli/st_cli/cmd/bootstrap.py (1)

875-877: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Thread backend into both egress vars_header calls. Line 1155 now passes the selected SecretBackend so the header describes the real secret store, but the two egress writers still use the default (None), producing an ansible-vault "stored encrypted in vault.yml" line for units bootstrapped in hashi_vault mode, where no vault.yml exists.

  • cli/st_cli/cmd/bootstrap.py#L875-L877: in _bundle_egress, pass backend as the 4th argument to writer.vars_header.
  • cli/st_cli/cmd/bootstrap.py#L928-L930: in _reuse_egress, pass backend as the 4th argument to writer.vars_header.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cli/st_cli/cmd/bootstrap.py` around lines 875 - 877, Update both
_bundle_egress (cli/st_cli/cmd/bootstrap.py:875-877) and _reuse_egress
(cli/st_cli/cmd/bootstrap.py:928-930) to pass the selected backend as the fourth
argument to writer.vars_header, matching the existing call around line 1155 so
generated headers reflect the actual secret store.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cli/st_cli/core/writer.py`:
- Around line 211-212: Update both _bundle_egress and _reuse_egress to pass
backend when calling vars_header, so generated egress headers reflect whether
component secrets are written. Make the success message near line 220
conditional on backend.component_secrets(...) being non-empty, and do not report
vault.yml as written when that collection is empty.

In `@cli/tests/test_bootstrap.py`:
- Around line 792-848: Add the scripted-questionnaire consumption assertion to
the projects bootstrap tests, including this test and the cases around the
referenced later scenarios: capture the return value of script_questionary in sq
and assert not sq._scripts after bootstrap completes. Preserve all existing
setup and behavioral assertions.

In `@docs/05-projects/01-projects.md`:
- Around line 145-147: Update the Containers troubleshooting command to replace
the hardcoded /opt/projects/projects path with the configured st_projects_dir
placeholder, using <st_projects_dir>/compose.yaml, and instruct operators to
substitute the actual configured directory.
- Around line 87-89: Update the Projects manifest’s requires declaration to
remove s3, so bootstrap does not list optional S3 configuration under required
preparation while preserving the questionnaire’s local-storage and S3 paths.

In `@roles/projects/defaults/main.yml`:
- Around line 36-37: The cAdvisor descriptions incorrectly claim direct
Prometheus and Loki integrations. Update the comment for
st_projects_cadvisor_enabled in roles/projects/defaults/main.yml (lines 36-37)
and its argument description in roles/projects/meta/argument_specs.yml (lines
69-72) to state that cAdvisor exposes metrics for Prometheus scraping, without
adding integrations.

---

Outside diff comments:
In `@cli/st_cli/cmd/bootstrap.py`:
- Around line 875-877: Update both _bundle_egress
(cli/st_cli/cmd/bootstrap.py:875-877) and _reuse_egress
(cli/st_cli/cmd/bootstrap.py:928-930) to pass the selected backend as the fourth
argument to writer.vars_header, matching the existing call around line 1155 so
generated headers reflect the actual secret store.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1649ad80-a140-4d74-9bec-d84fce4a2b3c

📥 Commits

Reviewing files that changed from the base of the PR and between fe1df52 and ffd7d2f.

📒 Files selected for processing (27)
  • README.md
  • changelogs/fragments/projects.yml
  • cli/st_cli/cmd/bootstrap.py
  • cli/st_cli/core/appmeta.py
  • cli/st_cli/core/envrender.py
  • cli/st_cli/core/resources/apps/drive.yml
  • cli/st_cli/core/resources/apps/keycloak.yml
  • cli/st_cli/core/resources/apps/meet.yml
  • cli/st_cli/core/resources/apps/messages.yml
  • cli/st_cli/core/resources/apps/projects.yml
  • cli/st_cli/core/resources/templates/env/projects.env.j2
  • cli/st_cli/core/writer.py
  • cli/tests/test_appmeta.py
  • cli/tests/test_bootstrap.py
  • cli/tests/test_envrender.py
  • cli/tests/test_writer.py
  • docs/05-projects/01-projects.md
  • roles/projects/REFERENCE.md
  • roles/projects/defaults/main.yml
  • roles/projects/meta/argument_specs.yml
  • roles/projects/meta/main.yml
  • roles/projects/tasks/deploy.yml
  • roles/projects/tasks/deploy/projects.yml
  • roles/projects/tasks/main.yml
  • roles/projects/templates/monitoring/compose_cadvisor.yaml.j2
  • roles/projects/templates/projects/compose.yaml.j2
  • roles/projects/templates/projects/env.j2

Comment thread cli/st_cli/core/writer.py
Comment on lines 211 to +212
expand_var_markers(data, backend)
data.yaml_set_start_comment(vars_header(app, meta, core))
data.yaml_set_start_comment(vars_header(app, meta, core, backend))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Propagate backend-aware messaging to all generated units.

Egress creation paths still call vars_header() without backend, so Hashi Vault/OpenBao egress configs claim secrets are encrypted in vault.yml even though none is written. Also make the Line 220 success message conditional for the same reason.

Proposed fix
- writer.vars_header(meta.app, meta, meta.component("egress"))
+ writer.vars_header(meta.app, meta, meta.component("egress"), backend)

Apply this to both _bundle_egress and _reuse_egress, and avoid reporting vault.yml as written when backend.component_secrets(...) is empty.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cli/st_cli/core/writer.py` around lines 211 - 212, Update both _bundle_egress
and _reuse_egress to pass backend when calling vars_header, so generated egress
headers reflect whether component secrets are written. Make the success message
near line 220 conditional on backend.component_secrets(...) being non-empty, and
do not report vault.yml as written when that collection is empty.

Comment thread cli/tests/test_bootstrap.py Outdated
Comment thread docs/05-projects/01-projects.md Outdated
Comment on lines +145 to +147
# Containers
podman-compose -f /opt/projects/projects/compose.yaml ps
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the configured Projects directory in the troubleshooting command.

The command hardcodes /opt/projects/projects, so it fails when st_projects_dir is overridden. Use a placeholder such as <st_projects_dir>/compose.yaml and instruct operators to substitute the configured value.

Based on roles/projects/defaults/main.yml Line 10.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/05-projects/01-projects.md` around lines 145 - 147, Update the
Containers troubleshooting command to replace the hardcoded
/opt/projects/projects path with the configured st_projects_dir placeholder,
using <st_projects_dir>/compose.yaml, and instruct operators to substitute the
actual configured directory.

Comment on lines +36 to +37
# Triggers the installation of the cadvisor container, used to send metrics to a Prometheus compatible server and logs to a Loki server.
st_projects_cadvisor_enabled: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the cAdvisor capability description.

Both descriptions claim that cAdvisor sends metrics to Prometheus and logs to Loki, but the supplied compose template only exposes cAdvisor’s metrics endpoint; no Loki forwarding or Prometheus destination is configured. Describe it as exposing metrics for Prometheus scraping, or add the missing integrations.

  • roles/projects/defaults/main.yml#L36-L37: update the default-variable comment.
  • roles/projects/meta/argument_specs.yml#L69-L72: update the argument description so generated documentation matches.

Based on roles/projects/templates/monitoring/compose_cadvisor.yaml.j2.

📍 Affects 2 files
  • roles/projects/defaults/main.yml#L36-L37 (this comment)
  • roles/projects/meta/argument_specs.yml#L69-L72
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@roles/projects/defaults/main.yml` around lines 36 - 37, The cAdvisor
descriptions incorrectly claim direct Prometheus and Loki integrations. Update
the comment for st_projects_cadvisor_enabled in roles/projects/defaults/main.yml
(lines 36-37) and its argument description in
roles/projects/meta/argument_specs.yml (lines 69-72) to state that cAdvisor
exposes metrics for Prometheus scraping, without adding integrations.

Comment thread roles/projects/meta/argument_specs.yml Outdated
Comment on lines +55 to +64
default:
- name: user-avatars
container_uid: 1000
container_path: /app/public/user-avatars
- name: project-background-images
container_uid: 1000
container_path: /app/public/project-background-images
- name: attachments
container_uid: 1000
container_path: /app/private/attachments

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

container_path should never be a var, these are fixed paths inside the container, we shouldn't put them there.

Comment thread roles/projects/templates/projects/compose.yaml.j2 Outdated
Comment thread roles/projects/meta/argument_specs.yml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
roles/projects/REFERENCE.md (1)

49-56: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Quote the task name in the playbook example.

The unquoted name value contains : , which makes this YAML invalid.

Proposed fix
-    - name: Importing role: suitenumerique.st.projects
+    - name: "Importing role: suitenumerique.st.projects"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@roles/projects/REFERENCE.md` around lines 49 - 56, Quote the task name value
in the playbook example under the task list, specifically the name beginning
with “Importing role:”, so the colon-space sequence is parsed as part of the
string and the YAML remains valid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@roles/projects/REFERENCE.md`:
- Around line 49-56: Quote the task name value in the playbook example under the
task list, specifically the name beginning with “Importing role:”, so the
colon-space sequence is parsed as part of the string and the YAML remains valid.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b5308242-8dcc-4467-a89d-7549a24bd7c6

📥 Commits

Reviewing files that changed from the base of the PR and between ffd7d2f and f749dfc.

📒 Files selected for processing (7)
  • cli/st_cli/cmd/bootstrap.py
  • cli/st_cli/core/resources/templates/env/projects.env.j2
  • cli/tests/test_bootstrap.py
  • roles/projects/REFERENCE.md
  • roles/projects/defaults/main.yml
  • roles/projects/meta/argument_specs.yml
  • roles/projects/templates/projects/compose.yaml.j2

@Nastaliss

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Nastaliss

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cli/st_cli/cmd/bootstrap.py (1)

319-328: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Collect the DATABASE_URL password using a masked prompt.

_ask() renders as questionary.text, so the password in DATABASE_URL is echoed while entered; _password() already exists and is used for other credential fields. Prompt the password with _password() and assemble the URL, or otherwise make the database URL entry explicitly non-echoing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cli/st_cli/cmd/bootstrap.py` around lines 319 - 328, Update the DATABASE_URL
collection in the bootstrap flow to avoid echoing the embedded password: replace
the plain-text _ask() entry with a masked _password()-based prompt, assembling
the complete URL as needed before passing it to backend.env_secret. Preserve the
existing prompts_values() conditional and DATABASE_URL storage behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@cli/st_cli/cmd/bootstrap.py`:
- Around line 319-328: Update the DATABASE_URL collection in the bootstrap flow
to avoid echoing the embedded password: replace the plain-text _ask() entry with
a masked _password()-based prompt, assembling the complete URL as needed before
passing it to backend.env_secret. Preserve the existing prompts_values()
conditional and DATABASE_URL storage behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fb3d051f-7ff9-4851-8387-3498f8a53061

📥 Commits

Reviewing files that changed from the base of the PR and between d5cedf2 and b5de6b1.

📒 Files selected for processing (6)
  • cli/st_cli/cmd/bootstrap.py
  • cli/st_cli/core/resources/apps/projects.yml
  • cli/st_cli/core/writer.py
  • cli/tests/test_appmeta.py
  • cli/tests/test_bootstrap.py
  • cli/tests/test_writer.py

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