{"id":34565869,"url":"https://github.com/johnfromspace/taskboard","last_synced_at":"2025-12-24T09:04:57.551Z","repository":{"id":327444213,"uuid":"1107061142","full_name":"JohnFromSpace/TaskBoard","owner":"JohnFromSpace","description":"A small C++ backend service used as a demo application for a Modern Practices in DevOps course final project.","archived":false,"fork":false,"pushed_at":"2025-12-05T21:42:14.000Z","size":43,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-06T22:11:09.988Z","etag":null,"topics":["backend","cmake","cmakelists","codeql","continuous-delivery","continuous-integration","cpp","devops","docker","docker-images","dockerfiles","ghcr","github-actions-enabled","github-workflows","gitops","infrastructure-as-code","k8s","kubernetes","kubernetes-cluster","sast"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JohnFromSpace.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-30T14:02:44.000Z","updated_at":"2025-12-05T21:42:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/JohnFromSpace/TaskBoard","commit_stats":null,"previous_names":["johnfromspace/taskboard"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/JohnFromSpace/TaskBoard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnFromSpace%2FTaskBoard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnFromSpace%2FTaskBoard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnFromSpace%2FTaskBoard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnFromSpace%2FTaskBoard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JohnFromSpace","download_url":"https://codeload.github.com/JohnFromSpace/TaskBoard/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JohnFromSpace%2FTaskBoard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27999339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","cmake","cmakelists","codeql","continuous-delivery","continuous-integration","cpp","devops","docker","docker-images","dockerfiles","ghcr","github-actions-enabled","github-workflows","gitops","infrastructure-as-code","k8s","kubernetes","kubernetes-cluster","sast"],"created_at":"2025-12-24T09:04:14.531Z","updated_at":"2025-12-24T09:04:57.543Z","avatar_url":"https://github.com/JohnFromSpace.png","language":"C++","readme":"# DevOps Taskboard\n\nThis project is a small C++ backend service used as a demo application for the **Modern Practices in DevOps** course final project.\n\nThe main focus is not on complex business logic, but on demonstrating a complete **CI/CD pipeline**, containerization, Kubernetes deployment, and basic security practices around the service.\n\n---\n\n## Project Goals\n\nThe project demonstrates:\n\n- Building and testing a C++ service with **CMake**\n- Packaging the service as a **Docker image**\n- Publishing images to **GitHub Container Registry (GHCR)**\n- Implementing **Continuous Integration (CI)** with GitHub Actions:\n  - Build, unit tests, Docker build\n- Implementing **Continuous Delivery (CD)** with GitHub Actions:\n  - Build \u0026 push Docker image\n  - Deploy to a **Kubernetes** cluster (ephemeral kind cluster in CI)\n  - Automatic `/health` smoke test inside the cluster\n- Applying key DevOps practices:\n  - Source control (Git + GitHub)\n  - Branching \u0026 pipelines\n  - Security / SAST (**CodeQL** analysis for C++)\n  - Infrastructure as Code (**Kubernetes manifests**)\n\n---\n\n## Service Overview\n\nCurrently the backend exposes a single HTTP endpoint:\n\n- `GET /health` – returns a small JSON payload indicating that the service is alive, e.g.:\n\n  ```json\n  {\n    \"status\": \"ok\",\n    \"service\": \"taskboard-backend\"\n  }\n\nThe implementation is intentionally minimal so that the main focus is on the DevOps pipeline and infrastructure (Docker, Kubernetes, CI/CD, security).\n\n---\n\n## Technologies\n\n* **Language:** C++17\n* **Build system:** CMake\n* **Tests:** Custom test runner + `ctest`\n* **Containers:** Docker (multi-stage build)\n* **Registry:** GitHub Container Registry (**GHCR**)\n* **Kubernetes:** kind (ephemeral cluster inside GitHub Actions) + K8s YAML manifests\n* **CI/CD:** GitHub Actions (`.github/workflows/ci.yml`, `.github/workflows/cd.yml`)\n* **Security / SAST:** GitHub **CodeQL** scanning for C++\n\n---\n\n## Repository Structure\n\nHigh-level layout:\n\n```bash\n.\n├─ backend/\n│  ├─ include/\n│  │  └─ http_responses.h          # Common HTTP response helpers\n│  ├─ src/\n│  │  ├─ main.cpp                  # Socket-based HTTP server + /health\n│  │  └─ http_responses.cpp        # Implementation of HTTP responses\n│  ├─ tests/\n│  │  └─ http_responses_tests.cpp  # Unit tests for HTTP response logic\n│  └─ CMakeLists.txt\n│\n├─ k8s/\n│  ├─ namespace.yaml               # Namespace: taskboard\n│  ├─ deployment.yaml              # Deployment: taskboard-backend\n│  └─ service.yaml                 # Service: taskboard-backend (ClusterIP)\n│\n├─ .github/\n│  └─ workflows/\n│     ├─ ci.yml                    # CI: build + tests + docker build\n│     └─ cd.yml                    # CD: build + push + deploy to Kubernetes (kind)\n│\n├─ CMakeLists.txt                  # Root CMake project\n├─ Dockerfile                      # Multi-stage Docker build\n├─ .dockerignore                   # Ignore build artifacts, .git, etc.\n└─ README.md\n```\n\n---\n\n## Local Build and Run\n\n### Option 1: CMake on Linux / WSL / MinGW\n\nFrom the project root:\n\n```bash\nmkdir -p build\ncd build\ncmake ..\ncmake --build . --config Release\n```\n\nThis produces (paths depend on your CMake generator):\n\n* `backend/taskboard_backend` – the server executable\n* `backend/taskboard_tests` – unit tests binary\n\nRun the backend:\n\n```bash\n./backend/taskboard_backend\n# The server listens on port 5000 by default\n```\n\nTest the `/health` endpoint:\n\n```bash\ncurl -v http://localhost:5000/health\n```\n\nYou should receive a JSON response similar to:\n\n```json\n{\"status\":\"ok\",\"service\":\"taskboard-backend\"}\n```\n\n### Option 2: Visual Studio (Windows)\n\n1. Open Visual Studio and use **“Open a local folder”** pointing to the repository root.\n2. Visual Studio will detect the CMake project automatically.\n3. Use **Build → Build All** (`Ctrl+Shift+B`) to build:\n\n   * `taskboard_core` static library\n   * `taskboard_backend` executable\n   * `taskboard_tests` executable\n4. Select `taskboard_backend` as the startup target and run (Ctrl+F5).\n5. Use `curl` or a browser to call `http://localhost:5000/health`.\n\n---\n\n## Unit Tests\n\nUnit tests are located in:\n\n* `backend/tests/http_responses_tests.cpp`\n\nThey validate:\n\n* Correct status lines:\n\n  * `HTTP/1.1 200 OK` for `/health`\n  * `HTTP/1.1 404 Not Found` for unknown paths\n* Presence of `Content-Type: application/json`\n* Correct JSON bodies for the responses\n\nRun tests locally via CTest:\n\n```bash\ncd build\nctest --output-on-failure\n```\n\nThe CI pipeline (`ci.yml`) runs the same `ctest` command on every push / pull request.\n\n---\n\n## Docker\n\n### Dockerfile\n\nThe root `Dockerfile` is a multi-stage build:\n\n1. **Builder stage**\n\n   * Base image: `debian:bookworm-slim`\n   * Installs `build-essential` and `cmake`\n   * Configures and builds the C++ project with CMake\n\n2. **Runtime stage**\n\n   * Base image: `debian:bookworm-slim`\n   * Copies only the compiled `taskboard_backend` binary from the builder stage\n   * Exposes port `5000`\n   * Starts the server via:\n\n     ```bash\n     ./taskboard_backend\n     ```\n\n### Local Docker Build (optional)\n\nIf you have Docker installed locally, you can build and run the image:\n\n```bash\ndocker build -t taskboard-backend:local .\ndocker run --rm -p 5000:5000 taskboard-backend:local\n\ncurl -v http://localhost:5000/health\n```\n\n---\n\n## Kubernetes\n\nKubernetes manifests are located in the `k8s/` directory:\n\n* `namespace.yaml` – defines the `taskboard` Namespace.\n* `deployment.yaml` – defines a `Deployment`:\n\n  * Name: `taskboard-backend`\n  * Namespace: `taskboard`\n  * 2 replicas\n  * Container image: `ghcr.io/johnfromspace/taskboard-backend:latest`\n  * Container port: `5000`\n  * `readinessProbe` and `livenessProbe` using the `/health` endpoint\n* `service.yaml` – defines a `ClusterIP` `Service`:\n\n  * Name: `taskboard-backend`\n  * Namespace: `taskboard`\n  * Service port: `80`\n  * Target port: `5000`\n  * Selector: `app: taskboard-backend`\n\n### Deploy with kind (as in the CD pipeline)\n\nThe CD pipeline uses **kind** (Kubernetes-in-Docker) inside GitHub Actions to create an ephemeral Kubernetes cluster for each run. The basic idea is:\n\n1. Create a kind cluster in the CI runner.\n2. Load the Docker image into the kind nodes.\n3. Apply the Kubernetes manifests.\n4. Wait for the rollout to finish.\n5. Port-forward the service and call `/health`.\n\nThis provides a real Kubernetes deployment and smoke test without requiring a persistent external cluster or local Docker Desktop.\n\n### Optional: Local Kubernetes with Docker Desktop\n\nIn addition to the CI/CD kind cluster, the same manifests can be tested against the local Kubernetes cluster provided by Docker Desktop.\n\n1. **Enable Kubernetes in Docker Desktop**\n\nOpen Docker Desktop → Settings → Kubernetes\n\nEnable \"Enable Kubernetes\" and apply the changes.\n\nAfter Kubernetes is running, verify:\n\n```bash\nkubectl config current-context\nkubectl get nodes\n```\n\nYou should see the docker-desktop context and a Ready node.\n\n2. **Apply project manifests**\n\nFrom the repository root:\n\n```bash\nkubectl apply -f k8s/namespace.yaml\nkubectl apply -f k8s/deployment.yaml\nkubectl apply -f k8s/service.yaml\n\nkubectl get pods -n taskboard\nkubectl get svc  -n taskboard\n```\n\nYou should see two taskboard-backend pods and a taskboard-backend service.\n\n3. **Use the locally built image (`taskboard-backend:local`)**\n\nIf you want to run exactly the same image you built locally (with `docker build -t taskboard-backend:local .`), you can update the deployment to use it:\n\n```bash\nkubectl set image deployment/taskboard-backend \\\n  taskboard-backend=taskboard-backend:local \\\n  -n taskboard\n```\n\nThen wait for the rollout:\n\n```bash\nkubectl rollout status deployment/taskboard-backend -n taskboard\nkubectl get pods -n taskboard\n```\n\n4. **Port-forward and test /health**\n\nExpose the service locally:\n\n```bash\nkubectl port-forward svc/taskboard-backend -n taskboard 5000:80\n```\n\nLeave this command running, then in another terminal:\n\n```bash\ncurl http://localhost:5000/health\n```\n\nExpected response:\n\n```json\n{\"status\":\"ok\",\"service\":\"taskboard-backend\"}\n```\n\nThis confirms that:\n\nThe application is running inside the local Kubernetes cluster.\n\nThe Service routes traffic correctly to the pods.\n\nThe `/health` endpoint is reachable through Kubernetes.\n\n5. **Clean up (optional)**\n\nTo remove the resources from the local cluster:\n\n```bash\nkubectl delete -f k8s/service.yaml\nkubectl delete -f k8s/deployment.yaml\nkubectl delete -f k8s/namespace.yaml\n# or simply:\n# kubectl delete namespace taskboard\n```\n\n---\n\n## CI Pipeline – `.github/workflows/ci.yml`\n\nThe **CI workflow** is responsible for:\n\n* Ensuring that the C++ code builds successfully.\n* Running unit tests.\n* Validating that the Dockerfile can build.\n\nKey steps:\n\n1. **Checkout**\n\n   ```yaml\n   - uses: actions/checkout@v4\n   ```\n\n2. **Install build tools**\n\n   ```yaml\n   - run: |\n       sudo apt-get update\n       sudo apt-get install -y --no-install-recommends \\\n         build-essential \\\n         cmake\n   ```\n\n3. **Configure \u0026 build with CMake**\n\n   ```yaml\n   - run: |\n       mkdir -p build\n       cd build\n       cmake ..\n       cmake --build . --config Release\n   ```\n\n4. **Run tests**\n\n   ```yaml\n   - run: |\n       cd build\n       ctest --output-on-failure\n   ```\n\n5. **Docker build sanity check**\n\n   ```yaml\n   - run: |\n       docker build -t taskboard-backend:ci .\n   ```\n\nPermissions are restricted to the minimum needed:\n\n```yaml\npermissions:\n  contents: read\n```\n\n---\n\n## CD Pipeline – `.github/workflows/cd.yml`\n\nThe **CD workflow** handles:\n\n* Building and pushing the Docker image to GHCR.\n* Deploying the application to a Kubernetes cluster (kind) inside GitHub Actions.\n* Running a smoke test against `/health`.\n\nHigh-level steps:\n\n1. **Checkout repository**\n\n2. **Set up Docker Buildx**\n\n3. **Log in to GHCR** using `github.token`\n\n4. **Build \u0026 push Docker image**\n\n   * Image tag format:\n\n     ```text\n     ghcr.io/\u003cowner\u003e/taskboard-backend:{sha, latest}\n     ```\n\n5. **Create a kind cluster** using `helm/kind-action`\n\n6. **Load the image into kind** to avoid pulling from the network\n\n7. **Apply Kubernetes manifests**\n\n   ```bash\n   kubectl apply -f k8s/namespace.yaml\n   kubectl apply -f k8s/deployment.yaml\n   kubectl apply -f k8s/service.yaml\n   ```\n\n8. **Wait for rollout**\n\n   ```bash\n   kubectl rollout status deployment/taskboard-backend -n taskboard\n   kubectl get pods -n taskboard\n   ```\n\n9. **Smoke test `/health` endpoint**\n\n   ```bash\n   kubectl port-forward svc/taskboard-backend -n taskboard 5000:80 \u0026\n   curl -f http://localhost:5000/health\n   ```\n\nIf any of these steps fail, the CD pipeline fails, ensuring that only healthy deployments are considered successful.\n\nPermissions:\n\n```yaml\npermissions:\n  contents: read\n  packages: write\n```\n\n---\n\n## Security \u0026 Quality\n\n* **Static Analysis (SAST):**\n  GitHub **CodeQL** code scanning is enabled for this repository via the Security tab. It analyzes the C++ code for common vulnerabilities and code issues.\n\n* **CI Hardening:**\n\n  * Minimal GitHub Actions `permissions` in both CI and CD workflows (principle of least privilege).\n  * Unit tests integrated into CI (pipeline fails if tests fail).\n\n* **Infrastructure as Code:**\n\n  * Kubernetes manifests are stored in version control.\n  * CI/CD workflows are defined as code in `.github/workflows/`.\n\n---\n\n## Possible Future Improvements\n\nThe current version focuses on the DevOps side. Possible extensions:\n\n* Implement a real TaskBoard API (tasks, statuses, priorities).\n* Add a database (e.g. PostgreSQL) and migrations (e.g. Flyway).\n* Introduce container image scanning (e.g. Trivy).\n* Add more advanced static analysis (clang-tidy, clang-format checks).\n* Add Ingress and TLS termination for external HTTPS access in Kubernetes.\n* Split the project into separate services (backend + frontend) and extend the pipeline accordingly.\n\nFor the purposes of the **Modern Practices in DevOps** course, the current implementation already demonstrates:\n\n* End-to-end CI/CD,\n* Docker-based delivery,\n* Deployment to Kubernetes,\n* Basic security and quality practices.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnfromspace%2Ftaskboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnfromspace%2Ftaskboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnfromspace%2Ftaskboard/lists"}