Skip to content

Fix production OpenFGA model rollout - #119

Merged
kl3inIT merged 2 commits into
mainfrom
fix/ai-admin-authorization
Jul 29, 2026
Merged

kl3inIT merged 2 commits into
mainfrom
fix/ai-admin-authorization

Conversation

@kl3inIT

@kl3inIT kl3inIT commented Jul 29, 2026 •

Copy link
Copy Markdown
Owner

Root cause

Production retained the authorization model ID created during the first OpenFGA bootstrap. New model relations such as can_manage_ai were present in the repository but never written and pinned in the running release, so legitimate organization admins received 403 responses on Language Models and Index Settings.

Fix

  • version the deployed OpenFGA model by SHA-256
  • write and pin a new immutable model before recreating application services when model bytes change
  • preserve the same store and tuples
  • make unchanged model deployments a no-op
  • restore the previous model ID and hash during deployment rollback
  • add a Linux regression contract covering bootstrap, legacy upgrade, no-op, and rollback
  • document the production lifecycle and architecture decision

This does not bypass OpenFGA or infer authorization from the UI role.

Verification

  • fga model validate: valid
  • OpenFGA model tests: 9/9 tests, 69/69 checks, 29/29 ListObjects
  • ShellCheck 0.11.0: passed
  • production Compose interpolation: passed
  • Linux rollout/no-op/rollback regression: passed
  • documentation checks: passed
  • git diff --check: passed

Summary by CodeRabbit

  • New Features

    • Production deployments now pin application requests to an immutable authorization model.
    • OpenFGA models are updated only when their contents change.
    • Failed deployments restore the previous application version and authorization model.
  • Bug Fixes

    • Improved consistency between application releases and authorization model configuration.
  • Documentation

    • Added production guidance for model bootstrapping, updates, and rollback behavior.
  • Tests

    • Added automated verification for initial rollout, no-op updates, and rollback scenarios.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

OpenFGA deployment now persists a model SHA-256 digest, conditionally writes models when the digest changes, restores prior configuration on rollback, and verifies bootstrap, rollout, no-op, and rollback behavior in CI.

Changes

OpenFGA model bootstrap

Layer / File(s) Summary
Model digest and environment persistence
infrastructure/deployment/production.env.example, infrastructure/deployment/scripts/bootstrap-openfga.sh, infrastructure/deployment/scripts/test-deploy-openfga-model-rollout.sh
Bootstrap computes and stores the model SHA-256 alongside the OpenFGA store and authorization model IDs.

Conditional deployment rollout

Layer / File(s) Summary
OpenFGA service and deployment wiring
infrastructure/deployment/compose.production.yaml, infrastructure/deployment/scripts/deploy.sh, ARCHITECTURE.md
Deployment waits for OpenFGA readiness, writes a model when its digest changes, updates the pinned model configuration, and documents rollback semantics.

Rollout and rollback verification

Layer / File(s) Summary
Integration scenarios and CI execution
infrastructure/deployment/scripts/test-deploy-openfga-model-rollout.sh, .github/workflows/ci.yml
The test verifies bootstrap, first rollout ordering, no-op deployment behavior, and restoration after a failed canary; CI runs the test during deployment verification.

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

Sequence Diagram(s)

sequenceDiagram
  participant deploy.sh
  participant OpenFGA
  participant openfga-model-write
  participant ApplicationStack
  deploy.sh->>OpenFGA: Start and await readiness
  deploy.sh->>openfga-model-write: Write model when SHA changes
  openfga-model-write-->>deploy.sh: Return authorization model ID
  deploy.sh->>ApplicationStack: Start release with pinned model configuration
Loading

Possibly related PRs

  • kl3inIT/OrgMemory#44: Adds the deployment and OpenFGA scaffolding modified here for model pinning and rollout verification.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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: fixing production OpenFGA model rollout behavior.
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 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ai-admin-authorization

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.

@kl3inIT
kl3inIT merged commit cd364fd into main Jul 29, 2026
13 of 14 checks passed

@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

🤖 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 `@infrastructure/deployment/compose.production.yaml`:
- Around line 199-201: Parameterize the OpenFGA compose service’s model volume
mount and the `/model/model.fga` argument to use the same overridable model-file
variable consumed by `deploy.sh` and `bootstrap-openfga.sh`, defaulting to the
current repository path. Ensure the digest input and model bytes written to
OpenFGA always come from the same file.
- Around line 190-218: Update the ORGMEMORY_OPENFGA_STORE_ID interpolation in
the openfga-model-write command to use the file’s required-variable fail-fast
syntax with a clear “Set ORGMEMORY_OPENFGA_STORE_ID” message, instead of
silently defaulting to an empty value. Preserve the existing command and service
configuration.

In `@infrastructure/deployment/scripts/deploy.sh`:
- Around line 105-137: Extract the duplicated env-file upsert awk logic from
update_openfga_model_configuration() in
infrastructure/deployment/scripts/deploy.sh (105-137) into a shared helper under
infrastructure/deployment/scripts/lib/env-file.sh that accepts key/value pairs
and the target file. Update
infrastructure/deployment/scripts/bootstrap-openfga.sh (81-119) so
update_environment_model() sources and uses this helper instead of its local awk
implementation; update_openfga_model_configuration() should use the same helper
while preserving replacement and append-at-EOF behavior.
- Around line 190-209: Make the model-write flow idempotent across failures
between openfga-model-write and update_openfga_model_configuration. Persist or
recover the successfully created model ID before retrying, and reuse it when the
repository digest is unchanged instead of creating another immutable model.
Update the logic around model_write_json, new_openfga_model_id, and
update_openfga_model_configuration while preserving the existing digest
comparison.
- Around line 190-205: The OpenFGA model-write command captured in
model_write_json must not allocate a pseudo-TTY, since its output is parsed as
JSON. Update the compose run invocation for openfga-model-write to include the
no-TTY option while preserving the existing profile, cleanup, and dependency
flags.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 94a39c38-f313-4a90-9a30-60325bb52e95

📥 Commits

Reviewing files that changed from the base of the PR and between 1595f7e and 76255e1.

⛔ Files ignored due to path filters (7)
  • docs/decisions/0017-pin-openfga-models-to-product-releases.md is excluded by !docs/**
  • docs/increments/active/2026-07-29-openfga-model-rollout/design.md is excluded by !docs/**
  • docs/increments/active/2026-07-29-openfga-model-rollout/plan.md is excluded by !docs/**
  • docs/roadmap.md is excluded by !docs/**
  • docs/runbooks/production-zm-deployment.md is excluded by !docs/**
  • docs/specs/domains/ai-model-control-plane.md is excluded by !docs/**
  • docs/tests/domains/ai-model-control-plane.md is excluded by !docs/**
📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • ARCHITECTURE.md
  • infrastructure/deployment/compose.production.yaml
  • infrastructure/deployment/production.env.example
  • infrastructure/deployment/scripts/bootstrap-openfga.sh
  • infrastructure/deployment/scripts/deploy.sh
  • infrastructure/deployment/scripts/test-deploy-openfga-model-rollout.sh
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Deployment contracts
  • GitHub Check: Public docs · Node 24
🧰 Additional context used
📓 Path-based instructions (4)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Always read the repository guidance and relevant sections of ARCHITECTURE.md; before changing a domain, read its specification, test-coverage document, and binding decision filenames.
Treat the repository as the engineering system of record; current repository and runtime evidence take precedence over chat or Northstar.
Read docs/guidelines/agent-safety.md before retrieval, AI, MCP, permission, upload, graph, or export work. Never commit secrets or customer data.

Files:

  • infrastructure/deployment/production.env.example
  • ARCHITECTURE.md
  • infrastructure/deployment/compose.production.yaml
  • infrastructure/deployment/scripts/bootstrap-openfga.sh
  • infrastructure/deployment/scripts/test-deploy-openfga-model-rollout.sh
  • infrastructure/deployment/scripts/deploy.sh
ARCHITECTURE.md

📄 CodeRabbit inference engine (CLAUDE.md)

Keep ARCHITECTURE.md limited to implemented facts, current project-wide facts, and commands; do not use it for intended or unimplemented behavior.

Files:

  • ARCHITECTURE.md
**/*.{java,gradle,gradle.kts,properties,yml,yaml}

📄 CodeRabbit inference engine (CLAUDE.md)

Before using unfamiliar Spring Boot 4, Spring Modulith 2, Spring AI 2, or Gradle APIs, consult current official documentation, Context7, and the relevant project verification skill.

Files:

  • infrastructure/deployment/compose.production.yaml
.github/**/*.{yml,yaml}

⚙️ CodeRabbit configuration file

.github/**/*.{yml,yaml}: Require least-privilege permissions, explicit release tags for actions,
bounded job timeouts, concurrency cancellation, frozen lockfiles, and no
secrets in pull-request workflows. GitHub Actions are intentionally not
pinned to commit SHAs; Dependabot owns their scheduled version updates.

Files:

  • .github/workflows/ci.yml
🧠 Learnings (2)
📚 Learning: 2026-07-27T14:53:53.633Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 92
File: infrastructure/deployment/compose.production.yaml:304-310
Timestamp: 2026-07-27T14:53:53.633Z
Learning: For OrgMemory’s Spring Boot SCIM configuration, the `application.yml`/`application-prod.yml` map `orgmemory.security.scim.*` properties via `${ORGMEMORY_SCIM_*}` placeholders. Therefore, in deployment Compose files and related environment/CI templates, set environment variables using the `ORGMEMORY_SCIM_*` names (e.g., `ORGMEMORY_SCIM_VERIFIER_KEY`) rather than “relaxed-binding-derived” names such as `ORGMEMORY_SECURITY_SCIM_*`. This is required to ensure Spring resolves the intended SCIM configuration properties.

Applied to files:

  • infrastructure/deployment/compose.production.yaml
📚 Learning: 2026-07-24T22:52:57.466Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 40
File: .github/workflows/ci.yml:126-126
Timestamp: 2026-07-24T22:52:57.466Z
Learning: In this repository’s GitHub Actions workflows, the `uses:` field may intentionally reference GitHub Actions by explicit release tags (not immutable commit SHAs) per the project’s OrgMemory policy. Do not flag tag-based `uses:` references as “unpinned” if they are release-tag-based (e.g., `owner/repovX.Y.Z`) and follow the repo’s Dependabot-owned scheduled updates approach.

Applied to files:

  • .github/workflows/ci.yml
🪛 ast-grep (0.45.0)
infrastructure/deployment/scripts/test-deploy-openfga-model-rollout.sh

[warning] 225-225: set +e (or set +o errexit) disables the shell's errexit option, so the script keeps running after a command fails. This masks failures of security-critical operations (downloads, signature/checksum verification, permission changes, cleanup of secrets), letting the script proceed with a bad or insecure state. Leave errexit enabled (set -e / set -euo pipefail), or handle failures explicitly with if/|| and an explicit exit instead of globally turning off failure detection.
Context: set +e
Note: [CWE-754] Improper Check for Unusual or Exceptional Conditions.

(set-plus-e-error-masking-bash)

🔇 Additional comments (9)
infrastructure/deployment/scripts/test-deploy-openfga-model-rollout.sh (2)

225-233: Static analysis false positive on set +e.

The set +e here is immediately paired with capturing status="$?", re-enabling set -e, and explicitly checking the captured status — the standard idiom for capturing an expected-failure exit code under errexit. This isn't masking an unusual condition; it's deliberately testing the rollback path. No change needed.

Source: Linters/SAST tools


1-251: LGTM!

infrastructure/deployment/production.env.example (1)

29-31: LGTM!

infrastructure/deployment/scripts/bootstrap-openfga.sh (2)

4-7: LGTM!


121-123: LGTM!

infrastructure/deployment/scripts/deploy.sh (2)

10-16: LGTM!


168-169: LGTM!

Also applies to: 187-189, 211-224

ARCHITECTURE.md (1)

416-422: LGTM! Accurately reflects the implemented bootstrap/deploy/rollback behavior verified elsewhere in this PR.

.github/workflows/ci.yml (1)

527-529: LGTM!

Comment on lines +190 to +218
openfga-model-write:
image: openfga/cli:v0.7.19@sha256:2e0e250043ef480a9162623dbf1ff7a62a1a2cb96a79cb20577b144994ab114d
profiles:
- ops
command:
- model
- write
- --store-id
- ${ORGMEMORY_OPENFGA_STORE_ID:-}
- --file
- /model/model.fga
- --format
- fga
- --api-url
- http://openfga:8080
depends_on:
openfga-ready:
condition: service_completed_successfully
networks:
- orgmemory-internal
volumes:
- ../../integrations/authorization-openfga/src/main/openfga/model.fga:/model/model.fga:ro
restart: "no"
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL

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

ORGMEMORY_OPENFGA_STORE_ID should fail fast like every other required variable in this file.

Line 198 uses ${ORGMEMORY_OPENFGA_STORE_ID:-} (silently empty default) while all other required variables in this file use :?Set VAR (e.g. line 63, 95, 291). If the store ID is ever empty (bootstrap failure, stale env, manual .env edit), fga model write --store-id "" will fail with an opaque CLI/API error mid-rollout instead of a clear pre-flight message, complicating incident response during exactly the kind of production rollout this PR is meant to make safer.

🛠️ Proposed fix
       - --store-id
-      - ${ORGMEMORY_OPENFGA_STORE_ID:-}
+      - ${ORGMEMORY_OPENFGA_STORE_ID:?Set ORGMEMORY_OPENFGA_STORE_ID}
📝 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
openfga-model-write:
image: openfga/cli:v0.7.19@sha256:2e0e250043ef480a9162623dbf1ff7a62a1a2cb96a79cb20577b144994ab114d
profiles:
- ops
command:
- model
- write
- --store-id
- ${ORGMEMORY_OPENFGA_STORE_ID:-}
- --file
- /model/model.fga
- --format
- fga
- --api-url
- http://openfga:8080
depends_on:
openfga-ready:
condition: service_completed_successfully
networks:
- orgmemory-internal
volumes:
- ../../integrations/authorization-openfga/src/main/openfga/model.fga:/model/model.fga:ro
restart: "no"
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
openfga-model-write:
image: openfga/cli:v0.7.19@sha256:2e0e250043ef480a9162623dbf1ff7a62a1a2cb96a79cb20577b144994ab114d
profiles:
- ops
command:
- model
- write
- --store-id
- ${ORGMEMORY_OPENFGA_STORE_ID:?Set ORGMEMORY_OPENFGA_STORE_ID}
- --file
- /model/model.fga
- --format
- fga
- --api-url
- http://openfga:8080
depends_on:
openfga-ready:
condition: service_completed_successfully
networks:
- orgmemory-internal
volumes:
- ../../integrations/authorization-openfga/src/main/openfga/model.fga:/model/model.fga:ro
restart: "no"
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
🤖 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 `@infrastructure/deployment/compose.production.yaml` around lines 190 - 218,
Update the ORGMEMORY_OPENFGA_STORE_ID interpolation in the openfga-model-write
command to use the file’s required-variable fail-fast syntax with a clear “Set
ORGMEMORY_OPENFGA_STORE_ID” message, instead of silently defaulting to an empty
value. Preserve the existing command and service configuration.

Comment on lines +199 to +201
- --file
- /model/model.fga
- --format

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 | 🔵 Trivial | ⚡ Quick win

Model source for digest vs. model write can silently diverge.

deploy.sh/bootstrap-openfga.sh compute the release SHA-256 from an overridable ORGMEMORY_OPENFGA_MODEL_FILE, but this compose service always mounts the hardcoded repo-relative path. If that override is ever used outside the test harness, the pinned digest would describe different bytes than what actually gets written into OpenFGA. Consider parameterizing this volume mount with the same variable (defaulting to the current hardcoded path) to keep the digest and the written model in sync, or document that the override is test-only.

Also applies to: 210-211

🤖 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 `@infrastructure/deployment/compose.production.yaml` around lines 199 - 201,
Parameterize the OpenFGA compose service’s model volume mount and the
`/model/model.fga` argument to use the same overridable model-file variable
consumed by `deploy.sh` and `bootstrap-openfga.sh`, defaulting to the current
repository path. Ensure the digest input and model bytes written to OpenFGA
always come from the same file.

Comment on lines +105 to +137
update_openfga_model_configuration() {
local model_id="$1"
local model_sha256="$2"
local temporary_file
temporary_file="$(mktemp)"

awk -v model_id="$model_id" -v model_sha256="$model_sha256" '
BEGIN {
values["ORGMEMORY_OPENFGA_AUTHORIZATION_MODEL_ID"] = model_id
values["ORGMEMORY_OPENFGA_MODEL_SHA256"] = model_sha256
}
{
split($0, parts, "=")
if (parts[1] in values) {
print parts[1] "=" values[parts[1]]
seen[parts[1]] = 1
} else {
print
}
}
END {
for (key in values) {
if (!seen[key]) {
print key "=" values[key]
}
}
}
' "$environment_file" > "$temporary_file"

install -m 0600 "$temporary_file" "$environment_file"
rm -f "$temporary_file"
}

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 | 🔵 Trivial | ⚡ Quick win

Extract the env-file key-upsert awk logic into a shared helper. Both new functions implement the identical "replace matching KEY= lines via awk, else append at EOF" pattern for persisting OpenFGA identifiers, duplicating the same logic (and echoing the pre-existing replace_image_references() in deploy.sh) across two scripts.

  • infrastructure/deployment/scripts/deploy.sh#L105-L137: extract update_openfga_model_configuration()'s awk body into a small shared shell library (e.g. infrastructure/deployment/scripts/lib/env-file.sh) that takes a set of key/value pairs and the target file.
  • infrastructure/deployment/scripts/bootstrap-openfga.sh#L81-L119: source the same shared helper for update_environment_model() instead of re-implementing the awk upsert.
📍 Affects 2 files
  • infrastructure/deployment/scripts/deploy.sh#L105-L137 (this comment)
  • infrastructure/deployment/scripts/bootstrap-openfga.sh#L81-L119
🤖 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 `@infrastructure/deployment/scripts/deploy.sh` around lines 105 - 137, Extract
the duplicated env-file upsert awk logic from
update_openfga_model_configuration() in
infrastructure/deployment/scripts/deploy.sh (105-137) into a shared helper under
infrastructure/deployment/scripts/lib/env-file.sh that accepts key/value pairs
and the target file. Update
infrastructure/deployment/scripts/bootstrap-openfga.sh (81-119) so
update_environment_model() sources and uses this helper instead of its local awk
implementation; update_openfga_model_configuration() should use the same helper
while preserving replacement and append-at-EOF behavior.

Comment on lines +190 to +205
if [[ "$openfga_model_sha256" != "$release_model_sha256" ]]; then
model_write_json="$(
"${compose[@]}" --profile ops run --rm --no-deps openfga-model-write
)"
new_openfga_model_id="$(
MODEL_WRITE_JSON="$model_write_json" python3 - <<'PY'
import json
import os

payload = json.loads(os.environ["MODEL_WRITE_JSON"])
model_id = payload.get("authorization_model_id") or payload.get("id")
if not model_id:
raise SystemExit("OpenFGA CLI response did not contain an authorization model id")
print(model_id)
PY
)"

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

🧩 Analysis chain

🌐 Web query:

Does docker compose run allocate a pseudo-TTY by default, and what flag disables it?

💡 Result:

By default, docker compose run automatically detects whether to allocate a pseudo-TTY [1][2][3]. It attempts to allocate a TTY if the command is run in an interactive terminal session [2]. If the input is not a terminal (for example, when piped or running in a CI/CD environment), it will default to disabling TTY allocation [2]. To explicitly disable pseudo-TTY allocation, you can use the -T or --no-tty flag [1][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repository guidance files =="
git ls-files | rg '(^|/)ARCHITECTURE\.md$|(^|/)agent-safety\.md$|(^|/)specification\.|test-coverage|binding decision|deploy\.sh$|docker-compose|compose' || true

echo
echo "== deploy.sh context =="
if [ -f infrastructure/deployment/scripts/deploy.sh ]; then
  wc -l infrastructure/deployment/scripts/deploy.sh
  sed -n '160,230p' infrastructure/deployment/scripts/deploy.sh | nl -ba -v160
fi

echo
echo "== openfga compose references =="
rg -n "openfga-model-write|docker compose|compose\\[" -S . || true

Repository: kl3inIT/OrgMemory

Length of output: 551


🌐 Web query:

Docker Compose run default TTY allocation documentation --no-TTY --no-tty

💡 Result:

In Docker Compose, the docker compose run command manages pseudo-TTY allocation with specific behaviors designed for interactive use [1]. TTY Allocation and Defaults By default, docker compose run attempts to allocate a pseudo-TTY if the command is run in an interactive environment [1]. However, to ensure compatibility with non-interactive environments (such as when input is being piped or redirected), Docker Compose performs automatic detection [1]. If the tool detects that it is not running in a terminal (i.e., dockerCli.Out().IsTerminal() is false), it will automatically disable TTY allocation [1]. The --no-tty and --no-TTY flags The --no-tty flag (with the shorthand -T) is used to explicitly disable pseudo-TTY allocation [2][3]. Regarding the variations --no-TTY and --no-tty: - Current versions of Docker Compose have normalized the flag to --no-tty [4]. - Historically, some versions and documentation variations used --no-TTY [5][4]. While recent updates have standardized this to the lowercase --no-tty to align with other commands like docker exec and improve consistency, many systems maintain support for both to avoid breaking existing scripts or workflows [4]. Summary of behavior: - Default: Auto-detected (allocates TTY if a terminal is present; disables it if not) [2][1]. - Explicit disable: Use --no-tty (or -T) to force-disable TTY allocation [2]. - Compatibility: Both --no-tty and --no-TTY generally function to achieve the same result in contemporary versions due to normalization efforts [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deploy.sh relevant lines =="
sed -n '1,230p' infrastructure/deployment/scripts/deploy.sh | awk '{printf "%6d\t%s\n", NR, $0}'

echo
echo "== compose files with openfga/model write services =="
rg -n "openfga|model-write|model_write|shell_escape|compose\\(" infrastructure apps compose.yaml docs/guidelines || true

echo
echo "== docker compose run flag docs in installed compose? =="
if command -v docker >/dev/null 2>&1; then
  docker compose version 2>/dev/null || true
  docker compose run --help 2>/dev/null | rg -i "tty|no-tty|no-TTY|detach" || true
else
  echo "docker not available"
fi

Repository: kl3inIT/OrgMemory

Length of output: 19207


Disable pseudo-TTY for the OpenFGA model-write capture.

docker compose run allocates a pseudo-TTY by default in interactive sessions, but model_write_json is parsed as JSON. Add the no-TTY flag to the capture command, e.g. openfga-model-write --no-tty, so the JSON remains valid when this rollout is run manually.

🤖 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 `@infrastructure/deployment/scripts/deploy.sh` around lines 190 - 205, The
OpenFGA model-write command captured in model_write_json must not allocate a
pseudo-TTY, since its output is parsed as JSON. Update the compose run
invocation for openfga-model-write to include the no-TTY option while preserving
the existing profile, cleanup, and dependency flags.

Comment on lines +190 to +209
if [[ "$openfga_model_sha256" != "$release_model_sha256" ]]; then
model_write_json="$(
"${compose[@]}" --profile ops run --rm --no-deps openfga-model-write
)"
new_openfga_model_id="$(
MODEL_WRITE_JSON="$model_write_json" python3 - <<'PY'
import json
import os

payload = json.loads(os.environ["MODEL_WRITE_JSON"])
model_id = payload.get("authorization_model_id") or payload.get("id")
if not model_id:
raise SystemExit("OpenFGA CLI response did not contain an authorization model id")
print(model_id)
PY
)"
update_openfga_model_configuration \
"$new_openfga_model_id" \
"$release_model_sha256"
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.

🚀 Performance & Scalability | 🔵 Trivial

Model-write is not idempotent across mid-step failures.

If the script fails after the immutable model write succeeds but before update_openfga_model_configuration commits the new ID/digest (e.g. the JSON parse step), the digest in the env file stays stale. A subsequent retry with unchanged repository bytes will write another duplicate immutable model, since the stored digest still won't match. This is low-risk given OpenFGA models are cheap and immutable by design, but worth being aware of for stores that see repeated failed rollout attempts (model list will accumulate inert versions over time).

🤖 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 `@infrastructure/deployment/scripts/deploy.sh` around lines 190 - 209, Make the
model-write flow idempotent across failures between openfga-model-write and
update_openfga_model_configuration. Persist or recover the successfully created
model ID before retrying, and reuse it when the repository digest is unchanged
instead of creating another immutable model. Update the logic around
model_write_json, new_openfga_model_id, and update_openfga_model_configuration
while preserving the existing digest comparison.

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