Skip to content

feat: deploy + CI/CD pipeline (#10)#12

Merged
CIKR-Repos merged 1 commit intomainfrom
feat/deploy-cicd
Feb 18, 2026
Merged

feat: deploy + CI/CD pipeline (#10)#12
CIKR-Repos merged 1 commit intomainfrom
feat/deploy-cicd

Conversation

@CIKR-Repos
Copy link
Owner

@CIKR-Repos CIKR-Repos commented Feb 18, 2026

Final PR! Adds Dockerfile, GitHub Actions CI/CD, fly.io config, and production configuration. Closes the PipeRAG MVP backlog.

Changes

  • Dockerfile — Multi-stage .NET 10 build (SDK → runtime, non-root user, healthcheck)
  • GitHub Actions CI/CD — Build, test, Docker push to GHCR, fly.io deploy
  • .dockerignore — Optimized build context
  • fly.toml — fly.io deployment config (IAD region, auto-stop/start)
  • appsettings.Production.json — Env var placeholders for all secrets
  • docker-compose.yml — Added production profile with API service
  • README.md — Deployment instructions (Docker, fly.io, CI/CD, env vars)

Summary by Sourcery

Introduce containerized production deployment and automated CI/CD for the application.

New Features:

  • Add Dockerfile for building and running the .NET API as a containerized service.
  • Add a production API service to docker-compose with environment configuration for core dependencies and secrets placeholders.
  • Configure fly.io application settings for running the API in a scaled-down, HTTPS-enabled production environment.

Enhancements:

  • Document deployment workflows for Docker, fly.io, and CI/CD, including required production environment variables.

CI:

  • Add GitHub Actions workflow to run build and tests on every PR and to build, publish, and deploy the Docker image to fly.io on pushes to main.

Documentation:

  • Expand README with deployment, CI/CD, and production environment variable documentation.

Tests:

  • Integrate test execution into the documented local development workflow and CI pipeline.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 18, 2026

Reviewer's Guide

Adds a production-ready containerization and deployment pipeline for PipeRAG using a multi-stage .NET 10 Docker image, GitHub Actions CI/CD, fly.io app configuration, and updated documentation/env configuration, including a production Docker Compose profile.

Sequence diagram for CI/CD workflow on PRs and main branch pushes

sequenceDiagram
  actor Developer
  participant GitHub
  participant GHA_CI as GitHub_Actions_CI
  participant GHCR as GitHub_Container_Registry
  participant Fly as fly_io

  rect rgb(230,230,250)
    Developer->>GitHub: Open_PR_to_main
    GitHub-->>GHA_CI: Trigger_build_and_test_workflow
    GHA_CI->>GHA_CI: Restore_dependencies
    GHA_CI->>GHA_CI: Build_API_Project
    GHA_CI->>GHA_CI: Restore_test_dependencies
    GHA_CI->>GHA_CI: Run_tests
    GHA_CI->>GitHub: Upload_test_results_artifact
    Note over GHA_CI,GHCR: For PRs, Docker image is built without push
    GHA_CI->>GHA_CI: Optional_Docker_build_no_push
  end

  rect rgb(220,255,220)
    Developer->>GitHub: Push_commit_to_main
    GitHub-->>GHA_CI: Trigger_build_and_test_job
    GHA_CI->>GHA_CI: Restore_build_test

    GitHub-->>GHA_CI: Trigger_docker_build_job
    GHA_CI->>GHCR: Login_with_GITHUB_TOKEN
    GHA_CI->>GHA_CI: Build_multi_stage_Docker_image
    GHA_CI->>GHCR: Push_image_tags_sha_and_latest

    GitHub-->>GHA_CI: Trigger_deploy_job
    GHA_CI->>Fly: flyctl_deploy_with_FLY_API_TOKEN
    Fly->>Fly: Pull_image_from_GHCR
    Fly-->>Developer: Deployed_new_version_to_piperag_app
  end
Loading

File-Level Changes

Change Details Files
Introduce multi-stage Docker build for the .NET API and production runtime configuration.
  • Add Dockerfile with .NET 10 preview multi-stage (SDK -> aspnet runtime) build and publish pipeline
  • Configure app to listen on port 8080 with ASPNETCORE_URLS and expose 8080
  • Run container as a non-root user for improved security
  • Add HTTP healthcheck that hits /health for container health monitoring
Dockerfile
Add GitHub Actions CI/CD workflow for build, test, image build/push to GHCR, and automated fly.io deploy.
  • Define CI/CD workflow triggers for pushes and pull requests to main
  • Add build-and-test job that restores, builds, and tests API and test projects, then uploads test results
  • Add docker-build job that logs into GHCR when pushing to main, generates image metadata, and builds/pushes Docker images
  • Add deploy job that uses flyctl to deploy the app to fly.io on successful pushes to main, using FLY_API_TOKEN secret
.github/workflows/ci.yml
Provide fly.io app configuration for production deployment.
  • Configure fly.io app name, primary region, and production ASPNETCORE_ENVIRONMENT
  • Expose HTTP service on internal port 8080 with HTTPS enforced and auto start/stop of machines
  • Set concurrency limits and minimal VM resources for the app
  • Add HTTP health check on /health for fly.io to monitor app health
fly.toml
Add production Docker Compose profile and API service wiring for local/production-like runs.
  • Introduce api service that builds from the local Dockerfile and runs in the production profile
  • Expose API on host port 8080 and depend on postgres and redis services
  • Wire environment variables for database, JWT, OpenAI, Stripe, and Redis into the api service
  • Keep existing postgres and redis service definitions and volumes for persistence
docker-compose.yml
Document local development, Docker/fly.io deployment, CI/CD behavior, and production environment variables.
  • Update development instructions to start postgres and redis with docker-compose and show how to run tests
  • Add Docker deployment section including build and production-profile compose usage with JWT and OpenAI env vars
  • Add fly.io deployment instructions, including secrets setup and deploy command
  • Document CI/CD pipeline behavior for PRs vs pushes to main and required FLY_API_TOKEN secret
  • Add table describing required production environment variables and their purpose
README.md
Add production-specific app configuration and Docker build context optimizations.
  • Introduce appsettings.Production.json with placeholders for production secrets via environment variables
  • Add .dockerignore to reduce Docker build context and improve image build performance
src/PipeRAG.Api/appsettings.Production.json
.dockerignore

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@CIKR-Repos CIKR-Repos merged commit 07fd18b into main Feb 18, 2026
1 of 2 checks passed
@CIKR-Repos CIKR-Repos deleted the feat/deploy-cicd branch February 18, 2026 04:20
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • The Dockerfile’s HEALTHCHECK uses curl but the mcr.microsoft.com/dotnet/aspnet:10.0-preview base image doesn’t include it by default, so the health check will fail unless you install curl (or switch to a check that uses a built-in tool like wget or dotnet itself).
  • In the docker-compose.yml production profile, the DATABASE_URL is hard-coded with development credentials; consider wiring this through environment variables or secrets so production-like runs don’t rely on embedded passwords.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The Dockerfile’s HEALTHCHECK uses `curl` but the `mcr.microsoft.com/dotnet/aspnet:10.0-preview` base image doesn’t include it by default, so the health check will fail unless you install `curl` (or switch to a check that uses a built-in tool like `wget` or `dotnet` itself).
- In the `docker-compose.yml` production profile, the `DATABASE_URL` is hard-coded with development credentials; consider wiring this through environment variables or secrets so production-like runs don’t rely on embedded passwords.

## Individual Comments

### Comment 1
<location> `docker-compose.yml:35` </location>
<code_context>
+      - "8080:8080"
+    environment:
+      ASPNETCORE_ENVIRONMENT: Production
+      DATABASE_URL: "Host=postgres;Database=piperag;Username=piperag;Password=piperag_dev"
+      JWT_SECRET: "${JWT_SECRET}"
+      OPENAI_API_KEY: "${OPENAI_API_KEY}"
</code_context>

<issue_to_address>
**🚨 issue (security):** Avoid hardcoding database credentials in the production docker-compose configuration.

`DATABASE_URL` currently includes the username and password inline, and even uses a `*_dev` password for a `Production` service. These credentials are easy to leak or accidentally reuse. Please switch to env interpolation for sensitive fields (e.g. `Password=${POSTGRES_PASSWORD}`) so secrets are managed via your environment/secret store instead of the compose file.
</issue_to_address>

### Comment 2
<location> `Dockerfile:31-32` </location>
<code_context>
+ENV ASPNETCORE_URLS=http://+:8080
+EXPOSE 8080
+
+HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
+    CMD curl -f http://localhost:8080/health || exit 1
+
+ENTRYPOINT ["dotnet", "PipeRAG.Api.dll"]
</code_context>

<issue_to_address>
**issue (bug_risk):** The healthcheck relies on `curl`, which is not present in the base ASP.NET runtime image.

In `mcr.microsoft.com/dotnet/aspnet` images `curl` is not installed, so this healthcheck will always fail with `command not found` even when the app is healthy. Please either install an HTTP client in the runtime image (e.g. via `apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*`) or change the healthcheck to use a built-in mechanism (for example a `dotnet`-based self-check) so it can run without extra packages.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

- "8080:8080"
environment:
ASPNETCORE_ENVIRONMENT: Production
DATABASE_URL: "Host=postgres;Database=piperag;Username=piperag;Password=piperag_dev"
Copy link

Choose a reason for hiding this comment

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

🚨 issue (security): Avoid hardcoding database credentials in the production docker-compose configuration.

DATABASE_URL currently includes the username and password inline, and even uses a *_dev password for a Production service. These credentials are easy to leak or accidentally reuse. Please switch to env interpolation for sensitive fields (e.g. Password=${POSTGRES_PASSWORD}) so secrets are managed via your environment/secret store instead of the compose file.

Comment on lines +31 to +32
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): The healthcheck relies on curl, which is not present in the base ASP.NET runtime image.

In mcr.microsoft.com/dotnet/aspnet images curl is not installed, so this healthcheck will always fail with command not found even when the app is healthy. Please either install an HTTP client in the runtime image (e.g. via apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*) or change the healthcheck to use a built-in mechanism (for example a dotnet-based self-check) so it can run without extra packages.

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