From a354e99ac825dadb6f6e5cd57f2a0b98ae517260 Mon Sep 17 00:00:00 2001 From: Jia Wei Date: Sat, 28 Feb 2026 14:48:44 +0100 Subject: [PATCH 1/6] Setup and adding pre-commit hooks --- .github/workflows/markdown2pdf.yml | 2 +- .pre-commit-config.yaml | 16 ++++ .secrets.baseline | 118 +++++++++++++++++++++++++++++ README.md | 28 +++---- 4 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 .secrets.baseline diff --git a/.github/workflows/markdown2pdf.yml b/.github/workflows/markdown2pdf.yml index fcb4671..4177b58 100644 --- a/.github/workflows/markdown2pdf.yml +++ b/.github/workflows/markdown2pdf.yml @@ -19,7 +19,7 @@ jobs: - name: Replace links run: | - cp README.md README_WITH_LINKS.md + cp README.md README_WITH_LINKS.md sed -i -e "s#\(^\!\[[^]]\+\](\)\(images/\)#\1$URL/\2#g" README_WITH_LINKS.md for file in sources/*; do sed -i -e "s#($file)#($URL/$file)#g" README_WITH_LINKS.md ; done diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d337d10..aaf3e35 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,3 +3,19 @@ repos: rev: v5.0.0 hooks: - id: trailing-whitespace + - id: check-added-large-files + - id: check-yaml + exclude: ^helm/fastapi-gitops-starter/templates + - repo: https://github.com/ibm/detect-secrets + rev: master + hooks: + - id: detect-secrets + args: [--baseline, .secrets.baseline, --use-all-plugins] + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.15.4 + hooks: + # Run the linter. + - id: ruff-check + # Run the formatter. + - id: ruff-format \ No newline at end of file diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000..eb04a18 --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,118 @@ +{ + "exclude": { + "files": "^.secrets.baseline$", + "lines": null + }, + "generated_at": "2026-02-28T13:44:41Z", + "plugins_used": [ + { + "name": "AWSKeyDetector" + }, + { + "name": "ArtifactoryDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "base64_limit": 4.5, + "name": "Base64HighEntropyString" + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "BoxDetector" + }, + { + "name": "CloudantDetector" + }, + { + "ghe_instance": "github.ibm.com", + "name": "GheDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "hex_limit": 3, + "name": "HexHighEntropyString" + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "keyword_exclude": null, + "name": "KeywordDetector" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "results": { + "helm/fastapi-gitops-starter/secret-example-canary-values.yaml": [ + { + "hashed_secret": "6e01f523d5b539497b7dd212e79e7182fa9a4cab", + "is_verified": false, + "line_number": 18, + "type": "Base64 High Entropy String", + "verified_result": null + }, + { + "hashed_secret": "e175c6f5f2a92e8623bd9a4820edb4e8c1b0fd10", + "is_verified": false, + "line_number": 18, + "type": "GitHub Token", + "verified_result": null + } + ], + "helm/fastapi-gitops-starter/secret-example-values.yaml": [ + { + "hashed_secret": "6e01f523d5b539497b7dd212e79e7182fa9a4cab", + "is_verified": false, + "line_number": 14, + "type": "Base64 High Entropy String", + "verified_result": null + }, + { + "hashed_secret": "e175c6f5f2a92e8623bd9a4820edb4e8c1b0fd10", + "is_verified": false, + "line_number": 14, + "type": "GitHub Token", + "verified_result": null + } + ] + }, + "version": "0.13.1+ibm.64.dss", + "word_list": { + "file": null, + "hash": null + } +} diff --git a/README.md b/README.md index 79bb814..057f54d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ GitOps with FastAPI ***University of Amsterdam*** -# 1. Introduction +# 1. Introduction In this tutorial, we use GitOps practices with FastAPI, including CI/CD pipelines, code quality tools, and automated testing. @@ -35,7 +35,7 @@ In this tutorial, we use GitOps practices with FastAPI, including CI/CD pipeline -# 2. Tutorial +# 2. Tutorial The steps of this tutorial are as follows: - [Building REST APIs with FastAPI](#21-setting-up-the-project) @@ -60,17 +60,17 @@ Prerequisites: ``` * Set Up the Python Environmentt: - + ```bash # Create a virtual environment python -m venv venv - + # Activate the virtual environment # On Linux/MacOS: source venv/bin/activate # On Windows: venv\Scripts\activate - + # Install dependencies pip install -r requirements.txt ``` @@ -110,7 +110,7 @@ Prerequisites: ```bash # Check for issues ruff check app/ tests/ - + # Fix auto-fixable issues ruff check app/ tests/ --fix ``` @@ -120,7 +120,7 @@ Prerequisites: ```bash # Check formatting black --check app/ tests/ - + # Format code black app/ tests/ ``` @@ -134,7 +134,7 @@ Pre-commit hooks automatically run checks before each commit to ensure consisten ```bash # Install pre-commit pip install pre-commit - + # Install the git hooks pre-commit install ``` @@ -142,11 +142,11 @@ Pre-commit hooks automatically run checks before each commit to ensure consisten * Using Pre-commit: Pre-commit will now run automatically on `git commit`. You can also run it manually: - + ```bash # Run on all files pre-commit run --all-files - + # Run on staged files pre-commit run ``` @@ -200,14 +200,14 @@ This repository includes a Helm chart for deploying the application to Kubernete - Kubernetes 1.19+ - Helm 3.0+ -* Install the Helm Chart: +* Install the Helm Chart: ```bash helm install my-release ./helm/fastapi-gitops-starter ``` -* Uninstall the Helm Chart: - +* Uninstall the Helm Chart: + ```bash helm uninstall my-release ``` @@ -239,7 +239,7 @@ including host and paths. * To make sure we do not commit secrets * To check code style - + ## 3.2 Add a New Endpoint 1. Open `app/main.py` From f81de4bfda3d6cc2f5fc0710f656ce691e602ae9 Mon Sep 17 00:00:00 2001 From: Jia Wei Date: Sat, 28 Feb 2026 15:14:34 +0100 Subject: [PATCH 2/6] Added new endpoint and modified github actions --- .github/workflows/ci-cd.yml | 2 ++ .vscode/launch.json | 21 +++++++++++++++++++++ app/main.py | 6 ++++++ tests/test_main.py | 9 +++++++++ 4 files changed, 38 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index a98b15e..f8c6e0f 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -18,6 +18,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + - name: Run Ruff + uses: astral-sh/ruff-action@v3 test: name: Run Tests diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7af9fda --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "cwd": "${workspaceFolder}\\\\app", + "name": "Python Debugger: FastAPI", + "type": "debugpy", + "request": "launch", + "module": "uvicorn", + "args": [ + "main:app", + "--reload" + ], + "jinja": true + } + ] +} \ No newline at end of file diff --git a/app/main.py b/app/main.py index ae8adc6..30abb95 100644 --- a/app/main.py +++ b/app/main.py @@ -49,5 +49,11 @@ async def get_item(item_id: int): } +@app.post("/api/items") +async def create_item(name: str, description: str): + """Create a new item.""" + return {"id": 999, "name": name, "description": description, "created": True} + + if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/tests/test_main.py b/tests/test_main.py index db89e2f..a8fc846 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -41,3 +41,12 @@ def test_get_item(): assert data["id"] == 5 assert data["name"] == "Item 5" assert "item number 5" in data["description"] + + +def test_create_item(): + """Test the create item endpoint.""" + response = client.post("/api/items?name=Test1&description=Desc1") + assert response.status_code == 200 + data = response.json() + assert data["name"] == "Test1" + assert data["description"] == "Desc1" From b988a777e703213cbac8264bf7aab7ac3a393bba Mon Sep 17 00:00:00 2001 From: Jia Wei Date: Sat, 28 Feb 2026 15:28:26 +0100 Subject: [PATCH 3/6] Implemented docker image build --- .github/workflows/ci-cd.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f8c6e0f..7427892 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -29,6 +29,17 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install dependencies + run: | + pip install pytest pytest-cov + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Run tests with coverage + run: | + pytest --cov=./ --cov-report=xml --cov-fail-under=80 build: name: Build Docker Image @@ -42,3 +53,23 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file From 4206447661614c06e1e3a591ad372ef55fff7cbc Mon Sep 17 00:00:00 2001 From: Jia Wei Date: Sat, 28 Feb 2026 15:31:54 +0100 Subject: [PATCH 4/6] Fixed workflow file --- .github/workflows/ci-cd.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 7427892..c211cd8 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -63,9 +63,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=raw,value=latest + images: ghcr.io/${{ github.repository }} - name: Build and push Docker image uses: docker/build-push-action@v5 with: From b1e468bf01102b8b0169a5acb1885b709924dc5d Mon Sep 17 00:00:00 2001 From: Jia Wei Date: Sat, 28 Feb 2026 15:37:08 +0100 Subject: [PATCH 5/6] Change docker location --- docker/Dockerfile => Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename docker/Dockerfile => Dockerfile (87%) diff --git a/docker/Dockerfile b/Dockerfile similarity index 87% rename from docker/Dockerfile rename to Dockerfile index 1ef04da..4bcd87d 100644 --- a/docker/Dockerfile +++ b/Dockerfile @@ -5,11 +5,11 @@ FROM python:3.11-slim WORKDIR /app # Install dependencies -COPY ../requirements.txt . +COPY ./requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy application code -COPY ../app ./app/ +COPY ./app ./app/ # Expose port 8000 EXPOSE 8000 From 6ccf99c11c9371eab1839aacd7d99034715a8779 Mon Sep 17 00:00:00 2001 From: Jia Wei Date: Sat, 28 Feb 2026 15:53:29 +0100 Subject: [PATCH 6/6] Fixed workflow file --- .github/workflows/ci-cd.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index c211cd8..04f5e93 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -64,6 +64,11 @@ jobs: uses: docker/metadata-action@v5 with: images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=raw,value=latest,enable={{is_default_branch}} - name: Build and push Docker image uses: docker/build-push-action@v5 with: