Skip to content

Deploy instructions#80

Merged
steflsd merged 1 commit into
mainfrom
feat/reference-deployment
Jul 17, 2026
Merged

Deploy instructions#80
steflsd merged 1 commit into
mainfrom
feat/reference-deployment

Conversation

@steflsd

@steflsd steflsd commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added a reference single-host deployment for the gateway, proxy, PostgreSQL, and supporting sidecars.
    • Added an idempotent installer that configures services, persistence, environment templates, and startup behavior.
    • Added fail-closed proxy policies for registry enforcement, secret detection, and PII detection.
    • Added local TLS and reverse-proxy configuration examples.
  • Documentation
    • Added setup, verification, troubleshooting, backup, restore, upgrade, and operational runbooks.
    • Added configuration templates with guidance for secrets, authentication, databases, and proxy settings.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds a single-host deployment reference with environment templates, fail-closed proxy policy, local PostgreSQL, Caddy configuration, an idempotent installer, systemd services, and operational documentation.

Changes

Reference deployment stack

Layer / File(s) Summary
Deployment configuration and policy
deploy/env/*, deploy/ficta-config.toml, deploy/docker-compose.postgres.yml, deploy/Caddyfile.example
Defines gateway and proxy environment templates, fail-closed detection settings, loopback PostgreSQL persistence, and internal-TLS reverse proxying.
Idempotent installation orchestration
deploy/install.sh
Installs host prerequisites, prepares the ficta account and repository, builds applications, starts containers, creates missing configuration, and enables runtime services.
Runtime services and operations
deploy/systemd/*, deploy/README.md
Defines hardened proxy and gateway systemd units and documents installation, verification, operations, backups, upgrades, and egress restrictions.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the changes, but it is too generic to identify the main deployment refactor. Use a more specific title such as "Add reference deployment docs and install scripts".
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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: 10

🧹 Nitpick comments (2)
deploy/install.sh (1)

71-73: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pass build paths as arguments, not interpolated shell code.

REPO_DIR is embedded inside bash -c; a path containing ' can append commands executed as ficta. This is not root-level injection because sudo -u ficta drops privileges, but it is still avoidable. Use runuser or an argument-safe command after changing directory in the parent shell.

🤖 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 `@deploy/install.sh` around lines 71 - 73, Update the install commands around
the dependency installation and package builds to avoid interpolating REPO_DIR
into bash -c shell code. Change the execution flow to pass the repository and
build paths as arguments using runuser or by changing directory in the parent
shell before invoking pnpm, while preserving execution as FICTA_USER and the
existing install/build commands.

Source: Linters/SAST tools

deploy/README.md (1)

3-6: 🔒 Security & Privacy | 🔵 Trivial

Do not present the egress allow-list as enforced by this stack.

Loopback bindings limit inbound exposure; they do not restrict outbound traffic from the host or Docker containers. Provide the firewall/network policy and a verification step, or clearly label this as an operator responsibility.

Also applies to: 126-131

🤖 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 `@deploy/README.md` around lines 3 - 6, Clarify the deployment README’s egress
statement so the stack does not claim to enforce the approved model-provider
allow-list. Label outbound firewall/network policy as an operator responsibility
and add the required policy and verification guidance if available; preserve the
existing description of loopback bindings as inbound exposure control.
🤖 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 `@deploy/env/gateway.env.example`:
- Around line 32-40: Update the authentication defaults in the gateway
environment example and the provider selection used by provider.server.ts so
deployments cannot silently run unauthenticated. Require an explicit
isolated-demo opt-in for AUTH_PROVIDER=none, or make WorkOS the default and fail
closed when its required configuration is absent; preserve unauthenticated mode
only when deliberately selected.

In `@deploy/install.sh`:
- Around line 7-8: Update the installer flow around REPO_URL and REPO_DIR to
accept a trusted branch, tag, or commit revision instead of implicitly using the
mutable default branch. Check out that requested revision, resolve and verify
its exact commit SHA, and record the resolved SHA before the build and
deployment steps so repeated installs are reproducible.
- Around line 80-92: Update the managed PostgreSQL branch in the install flow to
stop and remove the existing ficta-postgres container before logging that the
local container is skipped. Make the cleanup safe when the container does not
exist, while preserving the current local-container startup behavior in the else
branch.
- Around line 80-91: The local PostgreSQL setup block must not regenerate
credentials when an existing local database configuration is detected. Update
the `postgres.env` handling under the local-container branch: allow generated
credentials only for a first install, but if `gateway.env` already references
local PostgreSQL and `postgres.env` is missing, log an actionable error and
abort before starting Docker Compose; preserve the existing-file path.
- Around line 122-128: Update the startup gate around the CHANGE_ME grep in the
install flow to match only active assignment lines, ignoring commented examples
in gateway.env while still blocking startup for uncommented placeholders.
Preserve the existing logging and service-restart behavior in the surrounding
conditional.
- Line 68: Update the installation flow around the chown of REPO_DIR so the
built code under /opt/ficta remains root-owned and non-writable by runtime
services. Build before applying ownership and permissions, and place any
required mutable runtime state under /var/lib/ficta instead of making the
repository writable.
- Around line 42-45: Update the Node.js installation block around the node
version check to stop piping the remote NodeSource bootstrap directly into root
Bash. Vendor the bootstrap script or download it first, verify its pinned
checksum or signature, and execute it only after validation before installing
nodejs.

In `@deploy/README.md`:
- Line 8: Update the architecture fenced code block in the deployment README to
include an appropriate language identifier, such as text, immediately after the
opening fence so it satisfies markdownlint MD040.
- Around line 31-34: Correct the alternate install command in the deployment
README to invoke the existing deploy/install.sh script when run from the
repository root, while preserving the REPO_URL environment assignment and sudo
usage.
- Around line 89-116: Update the Restart / reboot, Backup, and Restore sections
to distinguish local PostgreSQL from managed DATABASE_URL deployments. Mark the
existing ficta-postgres docker commands as local-only, and provide equivalent
managed-database operational guidance or explicitly instruct operators to use
their provider’s backup and restore procedures.

---

Nitpick comments:
In `@deploy/install.sh`:
- Around line 71-73: Update the install commands around the dependency
installation and package builds to avoid interpolating REPO_DIR into bash -c
shell code. Change the execution flow to pass the repository and build paths as
arguments using runuser or by changing directory in the parent shell before
invoking pnpm, while preserving execution as FICTA_USER and the existing
install/build commands.

In `@deploy/README.md`:
- Around line 3-6: Clarify the deployment README’s egress statement so the stack
does not claim to enforce the approved model-provider allow-list. Label outbound
firewall/network policy as an operator responsibility and add the required
policy and verification guidance if available; preserve the existing description
of loopback bindings as inbound exposure control.
🪄 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: CHILL

Plan: Pro

Run ID: f749a64e-4da9-47df-9f19-d779cfa4e5c2

📥 Commits

Reviewing files that changed from the base of the PR and between a4e7a94 and 3e5e150.

📒 Files selected for processing (9)
  • deploy/Caddyfile.example
  • deploy/README.md
  • deploy/docker-compose.postgres.yml
  • deploy/env/gateway.env.example
  • deploy/env/proxy.env.example
  • deploy/ficta-config.toml
  • deploy/install.sh
  • deploy/systemd/ficta-gateway.service
  • deploy/systemd/ficta-proxy.service

Comment on lines +32 to +40
# --- Authentication: keep AUTH_PROVIDER=none ONLY on an isolated demo network.
# --- Production-like deployments use WorkOS AuthKit (Entra ID federation).
AUTH_PROVIDER=none
# AUTH_PROVIDER=workos
# FICTA_GATEWAY_ORG_ID=org_CHANGE_ME
# WORKOS_CLIENT_ID=CHANGE_ME
# WORKOS_API_KEY=CHANGE_ME
# WORKOS_REDIRECT_URI=https://gateway.example.internal/api/auth/callback
# WORKOS_COOKIE_PASSWORD=CHANGE_ME

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Do not ship an unauthenticated default for an exposed gateway.

AUTH_PROVIDER=none is the effective default; apps/gateway/src/lib/auth/provider.server.ts Lines 42-55 selects WorkOS only when the value is exactly workos. The warning comment is not an enforcement boundary, so a copy-paste deployment can expose the Gateway without authentication. Require an explicit isolated-demo opt-in, or default to WorkOS and fail closed when its configuration is missing.

🤖 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 `@deploy/env/gateway.env.example` around lines 32 - 40, Update the
authentication defaults in the gateway environment example and the provider
selection used by provider.server.ts so deployments cannot silently run
unauthenticated. Require an explicit isolated-demo opt-in for
AUTH_PROVIDER=none, or make WorkOS the default and fail closed when its required
configuration is absent; preserve unauthenticated mode only when deliberately
selected.

Comment thread deploy/install.sh
Comment on lines +7 to +8
REPO_URL="${REPO_URL:-https://github.com/SerovaAI/ficta.git}"
REPO_DIR="${REPO_DIR:-/opt/ficta}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Pin the revision that this installer builds.

Fresh installs clone the mutable default branch from REPO_URL, then build and deploy that result. This makes deployments non-reproducible and means the documented checkout invocation can deploy a different remote state than the checkout containing the installer. Accept a trusted branch/tag or commit, verify the resolved SHA, and record it before building.

Also applies to: 62-64

🤖 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 `@deploy/install.sh` around lines 7 - 8, Update the installer flow around
REPO_URL and REPO_DIR to accept a trusted branch, tag, or commit revision
instead of implicitly using the mutable default branch. Check out that requested
revision, resolve and verify its exact commit SHA, and record the resolved SHA
before the build and deployment steps so repeated installs are reproducible.

Comment thread deploy/install.sh
Comment on lines +42 to +45
if ! command -v node >/dev/null || [ "$(node -p 'process.versions.node.split(".")[0]')" -lt 20 ]; then
log "Node ${NODE_MAJOR}.x (NodeSource)"
curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash -
apt-get install -y -q nodejs

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '--- deploy/install.sh ---\n'
cat -n deploy/install.sh | sed -n '1,140p'
printf '\n--- NodeSource references ---\n'
rg -n "nodesource|setup_\$\{NODE_MAJOR\}|setup_[0-9]+\.x|NODE_MAJOR" deploy . -g '!**/node_modules/**'

Repository: SerovaAI/ficta

Length of output: 243


🏁 Script executed:

#!/bin/bash
set -e

echo '--- deploy/install.sh ---'
cat -n deploy/install.sh | sed -n '1,140p'

echo
echo '--- NodeSource references ---'
rg -n "nodesource|setup_\$\{NODE_MAJOR\}|setup_[0-9]+\.x|NODE_MAJOR" deploy . -g '!**/node_modules/**'

Repository: SerovaAI/ficta

Length of output: 7430


🌐 Web query:

NodeSource Debian Ubuntu setup script signed repository installation documentation setup_22.x curl bash

💡 Result:

To install Node.js 22.x on Debian or Ubuntu systems using the official NodeSource repository, use the following procedure. This method configures the signed NodeSource repository automatically on your system [1][2]. 1. Ensure required dependencies are installed: sudo apt update sudo apt install -y curl gnupg [2] 2. Run the NodeSource setup script: This script downloads, adds the NodeSource GPG signing key to your keyring, and configures the APT repository [1][2]. For Ubuntu: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - [3][2] For Debian (as root): curl -fsSL https://deb.nodesource.com/setup_22.x | bash - [4][5] 3. Install Node.js: After the script completes, install the Node.js package: sudo apt install -y nodejs [4][2] 4. Verify the installation: node -v npm -v [4][2] The NodeSource setup script (setup_22.x) is designed to handle repository configuration, including the installation of the GPG key to /usr/share/keyrings/nodesource.gpg to ensure signed package verification [1]. It is recommended to use the -E flag with sudo when executing the script to preserve environment variables, ensuring the script runs correctly under the user's shell environment [3][4].

Citations:


Avoid piping the NodeSource bootstrap script into root Bash. It still runs mutable remote code as root before any package verification; vendor the bootstrap script or pin and checksum/signature-check it before execution.

🧰 Tools
🪛 ast-grep (0.44.1)

[error] 43-43: Remote content fetched with curl/wget is piped directly into a shell interpreter, so any server compromise, MITM, or tampered mirror results in arbitrary code execution on this host. Download the script to a file first, verify its integrity (checksum/signature) and inspect it, then run the verified local copy.
Context: curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash -
Note: [CWE-494] Download of Code Without Integrity Check.

(curl-pipe-to-shell-bash)

🤖 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 `@deploy/install.sh` around lines 42 - 45, Update the Node.js installation
block around the node version check to stop piping the remote NodeSource
bootstrap directly into root Bash. Vendor the bootstrap script or download it
first, verify its pinned checksum or signature, and execute it only after
validation before installing nodejs.

Source: Linters/SAST tools

Comment thread deploy/install.sh
else
log "Checkout exists at ${REPO_DIR} (not pulling automatically — run git pull to upgrade)"
fi
chown -R "$FICTA_USER:$FICTA_USER" "$REPO_DIR"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the file and surrounding lines first
wc -l deploy/install.sh
sed -n '1,140p' deploy/install.sh

# Search for related ownership/runtime paths and systemd service definitions
rg -n --hidden --glob '!**/.git/**' 'FICTA_USER|REPO_DIR|/opt/ficta|/var/lib/ficta|chown -R|systemd|User=' deploy

Repository: SerovaAI/ficta

Length of output: 10490


🏁 Script executed:

#!/bin/bash
set -euo pipefail

wc -l deploy/systemd/ficta-proxy.service deploy/systemd/ficta-gateway.service
sed -n '1,120p' deploy/systemd/ficta-proxy.service
printf '\n---\n'
sed -n '1,120p' deploy/systemd/ficta-gateway.service

printf '\n---\n'
# Show any additional sandboxing/write controls in all systemd unit files
rg -n --hidden --glob '!**/.git/**' '^(ProtectSystem|ProtectHome|ReadOnlyPaths|ReadWritePaths|InaccessiblePaths|NoNewPrivileges|PrivateTmp|User=|Group=|WorkingDirectory=|ExecStart=)' deploy/systemd

Repository: SerovaAI/ficta

Length of output: 2586


🌐 Web query:

systemd ProtectSystem=full semantics /opt writable working directory

💡 Result:

When ProtectSystem=full is enabled in a systemd unit, it mounts /usr/, /boot/, /efi/, and /etc/ as read-only for the service [1][2]. Because /opt/ is not included in the list of directories protected by ProtectSystem=full, it remains accessible according to the default filesystem permissions [1][3]. If you need a service to write to a specific directory within /opt/ while using ProtectSystem=full, you have two primary methods to ensure write access: 1. ReadWritePaths=: You can explicitly allow-list the specific directory in /opt/ by adding it to the ReadWritePaths= directive in your unit file [1][2]. For example: ReadWritePaths=/opt/your-app/data 2. Directory-specific directives: If you are configuring a service to manage its own state or logs, you should ideally use the dedicated systemd directory directives, such as StateDirectory=, LogsDirectory=, or CacheDirectory= [1][3]. When these are used, systemd automatically creates the necessary directories in /var/lib/, /var/log/, or /var/cache/ (respectively) and ensures they are writable by the service, even if ProtectSystem= is active [1]. If your application strictly requires files to reside within /opt/ and you prefer not to use ReadWritePaths=, you must ensure the filesystem permissions outside of the systemd namespace already permit the service user to write to that location [4]. However, using ReadWritePaths= is the recommended approach for maintaining the security benefits of systemd sandboxing while selectively permitting necessary write access [1][2].

Citations:


Keep /opt/ficta out of the runtime write path.

chown -R "$FICTA_USER:$FICTA_USER" "$REPO_DIR" makes the code tree writable by the ficta services, so a runtime compromise can persist changes across restarts and bypass the intended ReadWritePaths=/var/lib/ficta boundary. Build first, then make /opt/ficta root-owned/read-only and keep mutable state under /var/lib/ficta.

🤖 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 `@deploy/install.sh` at line 68, Update the installation flow around the chown
of REPO_DIR so the built code under /opt/ficta remains root-owned and
non-writable by runtime services. Build before applying ownership and
permissions, and place any required mutable runtime state under /var/lib/ficta
instead of making the repository writable.

Comment thread deploy/install.sh
Comment on lines +80 to +91
if grep -qs '^DATABASE_URL=postgres' "$ENV_DIR/gateway.env" 2>/dev/null &&
! grep -qs '^DATABASE_URL=postgres://ficta:.*@127.0.0.1' "$ENV_DIR/gateway.env" 2>/dev/null; then
log "External DATABASE_URL configured — skipping local Postgres container"
else
log "Local Postgres container (loopback, persistent volume)"
if [ ! -f "$ENV_DIR/postgres.env" ]; then
install -d -m 0750 "$ENV_DIR"
printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 24)" > "$ENV_DIR/postgres.env"
chmod 600 "$ENV_DIR/postgres.env"
fi
docker compose -f "$REPO_DIR/deploy/docker-compose.postgres.yml" \
--env-file "$ENV_DIR/postgres.env" up -d --wait

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Fail instead of regenerating credentials for an existing local database.

If an existing gateway.env points to local PostgreSQL but postgres.env is missing, Lines 85-88 generate a new password. Existing gateway.env is not rewritten, and an existing database volume retains its original password, so the Gateway cannot connect. Only generate credentials on first install; otherwise abort and require credential recovery or explicit rotation.

🤖 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 `@deploy/install.sh` around lines 80 - 91, The local PostgreSQL setup block
must not regenerate credentials when an existing local database configuration is
detected. Update the `postgres.env` handling under the local-container branch:
allow generated credentials only for a first install, but if `gateway.env`
already references local PostgreSQL and `postgres.env` is missing, log an
actionable error and abort before starting Docker Compose; preserve the
existing-file path.

Comment thread deploy/install.sh
Comment on lines +80 to +92
if grep -qs '^DATABASE_URL=postgres' "$ENV_DIR/gateway.env" 2>/dev/null &&
! grep -qs '^DATABASE_URL=postgres://ficta:.*@127.0.0.1' "$ENV_DIR/gateway.env" 2>/dev/null; then
log "External DATABASE_URL configured — skipping local Postgres container"
else
log "Local Postgres container (loopback, persistent volume)"
if [ ! -f "$ENV_DIR/postgres.env" ]; then
install -d -m 0750 "$ENV_DIR"
printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 24)" > "$ENV_DIR/postgres.env"
chmod 600 "$ENV_DIR/postgres.env"
fi
docker compose -f "$REPO_DIR/deploy/docker-compose.postgres.yml" \
--env-file "$ENV_DIR/postgres.env" up -d --wait
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Remove the local container when switching to managed PostgreSQL.

The managed-database branch only skips starting PostgreSQL; it never stops or removes an existing ficta-postgres container. After an operator changes DATABASE_URL to a managed instance, the old local database continues running with restart: unless-stopped, retaining unnecessary sensitive state.

🤖 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 `@deploy/install.sh` around lines 80 - 92, Update the managed PostgreSQL branch
in the install flow to stop and remove the existing ficta-postgres container
before logging that the local container is skipped. Make the cleanup safe when
the container does not exist, while preserving the current local-container
startup behavior in the else branch.

Comment thread deploy/install.sh
Comment on lines +122 to +128
if grep -q 'CHANGE_ME' "$ENV_DIR/gateway.env"; then
log "NOT starting services: $ENV_DIR/gateway.env still contains CHANGE_ME placeholders."
echo " Edit it, then: systemctl restart ficta-proxy ficta-gateway"
else
systemctl restart ficta-proxy ficta-gateway
log "Services started."
fi

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 | 🟠 Major | ⚡ Quick win

Ignore commented CHANGE_ME examples when gating startup.

The gateway template contains commented WorkOS placeholders at Lines 36-40, so grep -q 'CHANGE_ME' remains true even when AUTH_PROVIDER=none and all active required values are configured. Services will therefore never start without manually deleting commented examples. Match only active assignments.

Proposed fix
-if grep -q 'CHANGE_ME' "$ENV_DIR/gateway.env"; then
+if grep -Eq '^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*=.*CHANGE_ME' "$ENV_DIR/gateway.env"; then
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if grep -q 'CHANGE_ME' "$ENV_DIR/gateway.env"; then
log "NOT starting services: $ENV_DIR/gateway.env still contains CHANGE_ME placeholders."
echo " Edit it, then: systemctl restart ficta-proxy ficta-gateway"
else
systemctl restart ficta-proxy ficta-gateway
log "Services started."
fi
if grep -Eq '^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*=.*CHANGE_ME' "$ENV_DIR/gateway.env"; then
log "NOT starting services: $ENV_DIR/gateway.env still contains CHANGE_ME placeholders."
echo " Edit it, then: systemctl restart ficta-proxy ficta-gateway"
else
systemctl restart ficta-proxy ficta-gateway
log "Services started."
fi
🤖 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 `@deploy/install.sh` around lines 122 - 128, Update the startup gate around the
CHANGE_ME grep in the install flow to match only active assignment lines,
ignoring commented examples in gateway.env while still blocking startup for
uncommented placeholders. Preserve the existing logging and service-restart
behavior in the surrounding conditional.

Comment thread deploy/README.md
[`apps/gateway/docs/poc-configuration.md`](../apps/gateway/docs/poc-configuration.md). One Linux
host runs the whole stack; the only external egress is the approved model-provider endpoint.

```

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

Specify the fenced block language.

The architecture block triggers markdownlint MD040. Use text or another appropriate language identifier.

🧰 Tools
🪛 markdownlint-cli2 (0.23.0)

[warning] 8-8: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@deploy/README.md` at line 8, Update the architecture fenced code block in the
deployment README to include an appropriate language identifier, such as text,
immediately after the opening fence so it satisfies markdownlint MD040.

Source: Linters/SAST tools

Comment thread deploy/README.md
Comment on lines +31 to +34
```sh
sudo ./deploy/install.sh # from a checkout, or:
sudo REPO_URL=https://github.com/SerovaAI/ficta.git ./install.sh
```

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

Fix the alternate install command path.

From the repository root, ./install.sh does not exist; the script is ./deploy/install.sh, so the documented alternative command fails.

🤖 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 `@deploy/README.md` around lines 31 - 34, Correct the alternate install command
in the deployment README to invoke the existing deploy/install.sh script when
run from the repository root, while preserving the REPO_URL environment
assignment and sudo usage.

Comment thread deploy/README.md
Comment on lines +89 to +116
**Restart / reboot**

```sh
sudo systemctl restart ficta-proxy ficta-gateway # services
sudo reboot # full host: everything must come back on its own
systemctl status ficta-proxy ficta-gateway # after reboot
docker ps # sidecars + postgres running
```

**Backup** (contains sensitive data — restored transcripts and the surrogate mapping; store per
the firm's policy)

```sh
docker exec ficta-postgres pg_dump -U ficta ficta | gzip > ficta-db-$(date +%F).sql.gz
sudo tar czf ficta-config-$(date +%F).tgz /etc/ficta /var/lib/ficta/.ficta \
/var/lib/ficta/protected-registry.json
```

`FICTA_GATEWAY_KEY_ENCRYPTION_SECRET` must be escrowed separately from the database backup —
backups contain encrypted workspace provider keys and are useless without it.

**Restore** (onto a host prepared by `install.sh`)

```sh
sudo systemctl stop ficta-gateway ficta-proxy
gunzip -c ficta-db-<date>.sql.gz | docker exec -i ficta-postgres psql -U ficta ficta
sudo tar xzf ficta-config-<date>.tgz -C /
sudo systemctl start ficta-proxy ficta-gateway

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make database runbook steps conditional on managed PostgreSQL.

The deployment supports managed DATABASE_URL, but the restart status, backup, and restore examples hard-code ficta-postgres. In managed mode that container is intentionally absent, so these operational instructions fail. Provide managed-database commands or clearly mark these steps as local-PostgreSQL-only.

🤖 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 `@deploy/README.md` around lines 89 - 116, Update the Restart / reboot, Backup,
and Restore sections to distinguish local PostgreSQL from managed DATABASE_URL
deployments. Mark the existing ficta-postgres docker commands as local-only, and
provide equivalent managed-database operational guidance or explicitly instruct
operators to use their provider’s backup and restore procedures.

@steflsd
steflsd merged commit 3e5e150 into main Jul 17, 2026
4 checks passed
@steflsd
steflsd deleted the feat/reference-deployment branch July 17, 2026 10:01
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