Skip to content

Add CF log bridge, workflows and drain infra - #424

Open
nlspnsgen wants to merge 1 commit into
stagingfrom
feat-route-cf-logs-and-metrics-to-stackit-observability
Open

Add CF log bridge, workflows and drain infra#424
nlspnsgen wants to merge 1 commit into
stagingfrom
feat-route-cf-logs-and-metrics-to-stackit-observability

Conversation

@nlspnsgen

@nlspnsgen nlspnsgen commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

We couldn't use the OTEL Collector Docker image here because it receives syslog over tcp not over https. CF can only send logs/metrics to a URL over https. So instead we are using Vector here. Its also a prebuilt Docker Image that deals with formatting and forwarding logs and metrics. We're pushing one Vector App per space.

Summary by CodeRabbit

  • New Features
    • Added centralized Cloud Foundry log and metric forwarding to Loki and Prometheus.
    • Added authenticated per-space log drain integration, including application and container metrics.
    • Added a deployable log bridge service with health monitoring and resilient buffering.
  • Documentation
    • Documented log bridge architecture, configuration, endpoints, authentication, labels, metrics, and validation.
  • Chores
    • Added automated image builds and deployments for staging and production environments.

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
baergpt-admin-panel Ready Ready Preview Aug 4, 2026 11:37am
baergpt-frontend Ready Ready Preview Aug 4, 2026 11:37am
baergpt-maintenance-mode Ready Ready Preview Aug 4, 2026 11:37am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds a Vector-based Cloud Foundry log bridge. Terraform creates per-space authenticated drains. GitHub Actions builds the image and deploys branch-specific applications with synchronized credentials and rolling updates.

Changes

Cloud Foundry bridge runtime

Layer / File(s) Summary
Bridge container and event pipelines
infra/cf-log-bridge/Dockerfile, infra/cf-log-bridge/manifest.yml, infra/cf-log-bridge/vector.yaml
Vector receives authenticated syslog events, routes logs to Loki, and converts gauge and counter events to Prometheus metrics.
Bridge configuration documentation
infra/cf-log-bridge/README.md
Documents deployment settings, event fields, endpoint formats, authentication, labels, and metric behavior.

Terraform drain provisioning

Layer / File(s) Summary
Drain variables and service instances
infra/terraform/cloud-foundry/variables.tf, infra/terraform/cloud-foundry/log-drain.tf
Adds validated per-space credentials and creates authenticated stackit-drain services for each Cloud Foundry space.
Application binding and Terraform documentation
apps/backend/manifest.yml, infra/terraform/cloud-foundry/README.md
Binds the backend to stackit-drain and documents the drain resource layout and credential synchronization.

Image publication and deployment

Layer / File(s) Summary
GHCR image workflow
.github/workflows/cf-log-bridge-image.yml
Builds the amd64 image, checks content-based tags, and publishes missing tags to GHCR.
Branch-specific deployment workflow
.github/workflows/cf-log-bridge-deploy.yml
Retrieves credentials, waits for the image, synchronizes application variables, bootstraps missing applications, performs rolling deployments, and collects logs after failures.

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

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant OnePassword
  participant GHCR
  participant CloudFoundry
  GitHubActions->>GHCR: Publish the content-tagged bridge image
  GitHubActions->>OnePassword: Retrieve deployment credentials and variables
  GitHubActions->>GHCR: Wait for the image tag
  GitHubActions->>CloudFoundry: Target the configured org and space
  GitHubActions->>CloudFoundry: Bootstrap or rolling-deploy the bridge
Loading

Possibly related PRs

Suggested reviewers: raphael-arce, tsboter

Poem

A rabbit packs Vector in a burrow so bright,
Sends logs to Loki and metrics in flight.
Terraform lays drains through each Cloud Foundry space,
GitHub rolls bridges to their proper place.
Tags hop to GHCR, credentials stay tight—
The bridge thumps its paws: “Deployed right!”

🚥 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 summarizes the primary changes: the CF log bridge, deployment workflows, and drain infrastructure.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-route-cf-logs-and-metrics-to-stackit-observability

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 @.github/workflows/cf-log-bridge-deploy.yml:
- Around line 94-100: Update the “Install cf CLI” step to use an exact Cloud
Foundry CLI release rather than the floating v8 URL, and verify the downloaded
artifact against its published checksum or signature before extracting it.
Ensure verification fails the workflow before any archive contents are extracted
or cf8 is moved into /usr/local/bin.

In @.github/workflows/cf-log-bridge-image.yml:
- Around line 3-14: Update the workflow triggers and job conditions in the
cf-log-bridge image workflow so pull_request runs only build the image without
GHCR login, existence checks, or publishing. Keep the GHCR authentication, tag
existence handling, and image push enabled for push and workflow_dispatch runs,
using the workflow’s existing job and step symbols.

In `@infra/terraform/cloud-foundry/log-drain.tf`:
- Around line 21-28: Update the syslog_drain_url construction to RFC 3986
percent-encode the username and password from var.drain_credentials[each.key]
separately before passing them to format(), while leaving the host and query
components unchanged.
🪄 Autofix

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 Plus

Run ID: bb20ad86-f7d7-43ff-9458-0095218f3965

📥 Commits

Reviewing files that changed from the base of the PR and between 4da6f8f and 2c3082a.

📒 Files selected for processing (10)
  • .github/workflows/cf-log-bridge-deploy.yml
  • .github/workflows/cf-log-bridge-image.yml
  • apps/backend/manifest.yml
  • infra/cf-log-bridge/Dockerfile
  • infra/cf-log-bridge/README.md
  • infra/cf-log-bridge/manifest.yml
  • infra/cf-log-bridge/vector.yaml
  • infra/terraform/cloud-foundry/README.md
  • infra/terraform/cloud-foundry/log-drain.tf
  • infra/terraform/cloud-foundry/variables.tf

Comment on lines +94 to +100
- name: Install cf CLI ⚙️
run: |
set -euo pipefail
curl -sL "https://packages.cloudfoundry.org/stable?release=linux64-binary&version=v8&source=github" \
| tar -zx
sudo mv cf8 /usr/local/bin/cf

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repo files matching workflow:"
git ls-files .github/workflows | sed -n '1,120p'

echo
echo "Target workflow relevant lines:"
if [ -f .github/workflows/cf-log-bridge-deploy.yml ]; then
  nl -ba .github/workflows/cf-log-bridge-deploy.yml | sed -n '1,150p'
else
  echo "missing target workflow"
fi

echo
echo "Cloud Foundry installs/usages in workflows:"
rg -n "packages.cloudfoundry.org|cf8|cf |OPER|CF_|login|cloud found|Cloud Foundry|GITHUB_ENV|1Password|op " .github/workflows || true

Repository: technologiestiftung/baergpt

Length of output: 862


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Target workflow lines:"
awk '{printf "%6d\t%s\n", NR, $0}' .github/workflows/cf-log-bridge-deploy.yml | sed -n '1,150p'

echo
echo "Relevant install/login/search patterns:"
grep -nE "packages.cloudfoundry.org|cf8|cf |login|OPER|CF_|GITHUB_ENV|op |1Password|permissions:|env:|environment:" .github/workflows/cf-log-bridge-deploy.yml || true

Repository: technologiestiftung/baergpt

Length of output: 9647


Other (CWE-494): Download of Code Without Integrity Check

Reachability: External

Verify the Cloud Foundry CLI artifact before execution.

The workflow stores Cloud Foundry credentials in GITHUB_ENV before downloading the CLI, and the install step fetches a floating v8 archive via tar, then installs cf8 globally. A compromised or replayed archive can execute under the deployment identity. Pin an exact cf release and check its published checksum or signature before extraction/install.

🤖 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 @.github/workflows/cf-log-bridge-deploy.yml around lines 94 - 100, Update the
“Install cf CLI” step to use an exact Cloud Foundry CLI release rather than the
floating v8 URL, and verify the downloaded artifact against its published
checksum or signature before extracting it. Ensure verification fails the
workflow before any archive contents are extracted or cf8 is moved into
/usr/local/bin.

Comment on lines +3 to +14
on:
pull_request:
branches: [staging, main]
paths: ["infra/cf-log-bridge/**", ".github/workflows/cf-log-bridge-image.yml"]
push:
branches: [staging, main]
paths: ["infra/cf-log-bridge/**", ".github/workflows/cf-log-bridge-image.yml"]
workflow_dispatch:

permissions:
contents: read
packages: write

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow file =="
if [ -f .github/workflows/cf-log-bridge-image.yml ]; then
  nl -ba .github/workflows/cf-log-bridge-image.yml | sed -n '1,140p'
else
  echo "missing .github/workflows/cf-log-bridge-image.yml"
  git ls-files .github/workflows | sed -n '1,120p'
fi

echo
echo "== related references =="
rg -n "cf-log-bridge|docker/build-push-action|GITHUB_TOKEN|GHCR|packages: write|pull_request|workflow_dispatch" .github/workflows -S || true

Repository: technologiestiftung/baergpt

Length of output: 225


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow file =="
if [ -f .github/workflows/cf-log-bridge-image.yml ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' .github/workflows/cf-log-bridge-image.yml | sed -n '1,140p'
else
  echo "missing .github/workflows/cf-log-bridge-image.yml"
  git ls-files .github/workflows | sed -n '1,120p'
fi

echo
echo "== related references =="
rg -n "cf-log-bridge|docker/build-push-action|GITHUB_TOKEN|GHCR|packages: write|pull_request|workflow_dispatch" .github/workflows -S || true

Repository: technologiestiftung/baergpt

Length of output: 9147


🌐 Web query:

GitHub pull requests from forks secrets.GITHUB_TOKEN read-only packages write permissions

💡 Result:

When a workflow is triggered by a pull request from a public fork, GitHub security policies enforce a read-only GITHUB_TOKEN, regardless of the permissions configured in your workflow file [1][2][3]. This restriction is a security boundary designed to prevent untrusted code submitted via forks from executing with write access to your repository [4][2]. Key details regarding this behavior include: 1. Restriction on Write Access: For pull requests from forks using the standard pull_request event, all requested write permissions (such as packages: write or contents: write) are automatically downgraded to read-only [1][5][6]. You cannot override this downgrade using the permissions key in your YAML file [2][3]. 2. Exception for pull_request_target: The pull_request_target event is an exception to this rule [6][7]. Because it runs in the context of the base repository's default branch rather than the fork's merge commit, it is granted the repository's standard permissions, which can include write access [4][2]. Important Security Warning: While pull_request_target allows for write permissions, it should be used with caution [3]. Because it executes code from the base repository's default branch, you must ensure you are not checking out or executing untrusted code from the pull request itself in a way that could lead to security vulnerabilities [4][2][3]. 3. Recommended Patterns: To handle tasks like publishing packages or commenting on pull requests from forks, the industry-standard approach is often to use a two-workflow split [2]: - An untrusted pull_request workflow that performs builds and uploads artifacts. - A separate, trusted workflow_run or pull_request_target job that consumes those artifacts and performs the authorized write actions [2]. For further configuration, repository administrators can control whether fork pull requests are allowed to send write tokens to workflows at all via the repository's Actions settings under "Workflow permissions" [8][5], though this still respects the fundamental security downgrade for the pull_request event [5].

Citations:


🌐 Web query:

docker/build-push-action v7 not authenticated without login registry GHCR GITHUB_TOKEN permissions packages write

💡 Result:

To use docker/build-push-action v7 to push images to the GitHub Container Registry (GHCR) without manually running a separate docker/login-action, you must configure the workflow to authenticate using the GitHub Actions GITHUB_TOKEN and ensure the appropriate permissions are set [1]. Authentication Setup: You can authenticate to GHCR using the GITHUB_TOKEN provided by the workflow environment [1][2]. The action and the underlying Buildx setup will use this token to authenticate against ghcr.io if configured correctly [1]. Permissions Required: Your workflow must have explicit write permissions for the packages scope [1][3][4]. This is configured in the permissions block of your workflow file: permissions: contents: read packages: write Implementation: Because docker/build-push-action relies on Docker Buildx, you must ensure Buildx is set up before the build step using docker/setup-buildx-action [5][4]. While docker/login-action is commonly used, you can authenticate against GHCR by passing the GITHUB_TOKEN to the login step: - name: Login to GHCR uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} Although you asked to push without login, the docker/build-push-action requires an active Docker daemon authentication to push to a private registry [5][6]. Using docker/login-action with the GITHUB_TOKEN is the standard, secure way to provide this authentication without needing a long-lived Personal Access Token (PAT) [1]. Ensuring your workflow has packages: write is the critical security requirement for this token to successfully push images to your GHCR repository [1][4].

Citations:


Do not publish images during pull_request runs.

secrets.GITHUB_TOKEN is read-only for fork pull requests. When a new content tag is encountered, GitHub Container Registry login fails before docker/build-push-action reaches the build job. Use a build-only path for pull_request, and keep the GHCR login/existence check/push for push or workflow_dispatch.

[low_effort And_high_reward]

🤖 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 @.github/workflows/cf-log-bridge-image.yml around lines 3 - 14, Update the
workflow triggers and job conditions in the cf-log-bridge image workflow so
pull_request runs only build the image without GHCR login, existence checks, or
publishing. Keep the GHCR authentication, tag existence handling, and image push
enabled for push and workflow_dispatch runs, using the workflow’s existing job
and step symbols.

Comment on lines +21 to +28
syslog_drain_url = format(
"https://%s:%s@%s-%s.%s/?drain-type=all",
var.drain_credentials[each.key].username,
var.drain_credentials[each.key].password,
var.log_bridge_app_name,
each.key,
var.apps_domain,
)

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

Percent-encode both credential components.

The code inserts arbitrary credentials directly into URL userinfo. Reserved characters can change the parsed authority or make the drain URL invalid. A valid rotated password can therefore stop telemetry delivery.

Apply RFC 3986 percent-encoding separately to the username and password before format() constructs the URL.

🧰 Tools
🪛 Checkov (3.3.8)

[medium] 22-23: Basic Auth Credentials

(CKV_SECRET_4)

🤖 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 `@infra/terraform/cloud-foundry/log-drain.tf` around lines 21 - 28, Update the
syslog_drain_url construction to RFC 3986 percent-encode the username and
password from var.drain_credentials[each.key] separately before passing them to
format(), while leaving the host and query components unchanged.

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