From a118d1275fa8c238d405f8bc2771777e3f14b40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9mence=20Lesn=C3=A9?= Date: Fri, 12 Jan 2024 13:08:04 +0100 Subject: [PATCH 1/5] fix: More pleasant sounds with distorsion on call --- resources/acknowledge.mp3 | Bin 10770 -> 7838 bytes resources/ready.mp3 | Bin 18210 -> 13982 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/acknowledge.mp3 b/resources/acknowledge.mp3 index dd166d51769c0cf8c9165f1e2f0d1e5ea2a85910..2babd96cf4183bee2234a43f010dd2b8ea304f86 100644 GIT binary patch literal 7838 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 diff --git a/resources/ready.mp3 b/resources/ready.mp3 index 72fcdc5b0a0b5d432f63a491353d6a7d7d62ab62..c52cb62fdab7afbb5f6a9029b9340f1c3c3fc667 100644 GIT binary patch literal 13982 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 literal 18210 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 From 9b2c71dd95a1fa94239d08d00d706304c42658fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9mence=20Lesn=C3=A9?= Date: Fri, 12 Jan 2024 13:12:02 +0100 Subject: [PATCH 2/5] dev: Package app into a container --- Dockerfile | 36 ++++++++++++++++++++++++++++++++++++ Makefile | 8 ++++++++ 2 files changed, 44 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..f8541416 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +# Base container +FROM docker.io/library/python:3.11-slim-bullseye@sha256:9f35f3a6420693c209c11bba63dcf103d88e47ebe0b205336b5168c122967edf AS base + +# Build container +FROM base AS build + +RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked --mount=target=/root/.cache/pip,type=cache,sharing=locked \ + apt-get update \ + && apt-get install --yes gcc python3-dev \ + && python3 -m pip install --upgrade pip setuptools wheel + +RUN python -m venv /venv +ENV PATH=/venv/bin:$PATH + +COPY requirements.txt . +RUN --mount=target=/root/.cache/pip,type=cache,sharing=locked \ + python3 -m pip install --requirement requirements.txt + +# Output container +FROM base + +ARG VERSION +ENV VERSION=${VERSION} + +RUN useradd -m appuser \ + && mkdir /app \ + && chown -R appuser:appuser /app + +USER appuser + +COPY --from=build /venv /venv +ENV PATH=/venv/bin:$PATH + +COPY --chown=appuser:appuser . /app + +CMD ["bash", "-c", "cd /app && uvicorn main:api --host 0.0.0.0 --port 8080 --proxy-headers --no-server-header --timeout-keep-alive 60 --header x-version:${VERSION}"] diff --git a/Makefile b/Makefile index 75094583..c154530a 100644 --- a/Makefile +++ b/Makefile @@ -50,3 +50,11 @@ start: --port 8080 \ --proxy-headers \ --reload + + +build: + $(docker) build \ + --build-arg VERSION=$(version_full) \ + --tag $(container_name):$(version_small) \ + --tag $(container_name):latest \ + . From 33868a8f41568ffcf89edd7cc02b92ffaaaa994b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9mence=20Lesn=C3=A9?= Date: Fri, 12 Jan 2024 13:22:12 +0100 Subject: [PATCH 3/5] security: Automatically update deps with Dependabot --- .github/dependabot.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..bd7cf876 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: "" + target-branch: develop + schedule: + interval: daily + - package-ecosystem: pip + directory: "" + target-branch: develop + schedule: + interval: daily + - package-ecosystem: docker + directory: "" + target-branch: develop + schedule: + interval: daily From 5ac167813999f146b2bdaf17fb0032f8677a13e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9mence=20Lesn=C3=A9?= Date: Fri, 12 Jan 2024 13:55:41 +0100 Subject: [PATCH 4/5] dev: Pre-configure VSCode IDE --- .vscode/settings.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..4c1fb770 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnPaste": true, + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "modifications", + "python.analysis.typeCheckingMode": "basic", + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter" + } +} From 7a4f24a4c4a0625114c2f9091ef3198e0afab0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9mence=20Lesn=C3=A9?= Date: Fri, 12 Jan 2024 13:55:46 +0100 Subject: [PATCH 5/5] dev: Automated test/build with GitHub Actions --- .github/workflows/pipeline.yaml | 227 ++++++++++++++++++++++++++++++++ Dockerfile | 19 ++- Makefile | 12 ++ README.md | 9 +- 4 files changed, 262 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/pipeline.yaml diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml new file mode 100644 index 00000000..821b9aa5 --- /dev/null +++ b/.github/workflows/pipeline.yaml @@ -0,0 +1,227 @@ +name: pipeline + +on: + push: + branches: + - develop + - feat/* + - hotfix/* + - main + pull_request: + branches: + - develop + - feat/* + - hotfix/* + - main + +env: + CONTAINER_NAME: ${{ github.repository }} + CONTAINER_REGISTRY_GHCR: ghcr.io + CONTAINER_PLATFORMS: linux/amd64,linux/arm64/v8 + # https://github.com/docker/buildx/releases + BUILDX_VERSION: 0.11.2 + +jobs: + init: + name: Init + runs-on: ubuntu-22.04 + outputs: + VERSION: ${{ steps.version.outputs.version }} + VERSION_FULL: ${{ steps.version.outputs.version_full }} + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + with: + # We need all Git history for "version.sh" + fetch-depth: 0 + # Ensure "version.sh" submodule are up-to-date + submodules: recursive + + - name: Version + id: version + run: | + echo "version=$(bash cicd/version/version.sh -g . -c)" >> $GITHUB_OUTPUT + echo "version_full=$(bash cicd/version/version.sh -g . -c -m)" >> $GITHUB_OUTPUT + + sast-creds: + name: SAST - Credentials + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + with: + # We need all Git history for testing credentials + fetch-depth: 0 + # Ensure all submodules up-to-date + submodules: recursive + + - name: SAST - Credentials + uses: trufflesecurity/trufflehog@v3.63.1 + with: + base: ${{ github.event.repository.default_branch }} + extra_args: --only-verified + head: HEAD + path: . + + build-image: + name: Build & publish image + needs: + - init + - sast-creds + - sast-semgrep + runs-on: ubuntu-22.04 + permissions: + # Allow to write to GitHub Packages + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + + - name: Configure Git + run: | + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor }}@users.noreply.github.com" + + - name: Setup QEMU + id: setup-qemu + uses: docker/setup-qemu-action@v3.0.0 + with: + platforms: ${{ env.CONTAINER_PLATFORMS }} + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + with: + version: v${{ env.BUILDX_VERSION }} + + - name: Login to registry - GitHub + uses: docker/login-action@v3.0.0 + with: + registry: ${{ env.CONTAINER_REGISTRY_GHCR }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Container meta + id: meta + uses: docker/metadata-action@v5.0.0 + with: + images: ${{ env.CONTAINER_REGISTRY_GHCR }}/${{ env.CONTAINER_NAME }} + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=ref,event=branch + type=ref,event=pr + type=schedule + type=schedule,pattern={{date 'YYYYMMDD'}} + type=semver,pattern={{version}},value=${{ needs.init.outputs.VERSION_FULL }} + type=sha + labels: | + org.opencontainers.image.documentation=https://github.com/${{ env.CONTAINER_NAME }} + org.opencontainers.image.vendor=${{ github.actor }} + + - name: Store tag + id: tag + run: | + branch=$(echo "${{ github.ref_name }}" | sed 's/\//-/g') + tag=$(echo "${{ steps.meta.outputs.tags }}" | grep -m1 $branch) + echo "tag=$tag" >> $GITHUB_OUTPUT + + - name: Build/push container + uses: docker/build-push-action@v5.0.0 + with: + build-args: | + VERSION=${{ needs.init.outputs.VERSION_FULL }} + cache-from: type=gha + cache-to: type=gha + context: . + labels: ${{ steps.meta.outputs.labels }} + platforms: ${{ env.CONTAINER_PLATFORMS }} + provenance: true + push: true + sbom: true + tags: ${{ steps.meta.outputs.tags }} + + sast-semgrep: + name: SAST - Semgrep + runs-on: ubuntu-22.04 + permissions: + # Allow to write to GitHub Security + security-events: write + container: + image: returntocorp/semgrep + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + + - name: Run tests + # Semgrep can be used to break the build when it detects security issues. In this case we want to upload the issues to GitHub Security + continue-on-error: true + env: + SEMGREP_RULES: p/cwe-top-25 p/owasp-top-ten p/dockerfile + run: semgrep ci --sarif --output=semgrep.sarif + + - name: Upload results to GitHub Security + uses: github/codeql-action/upload-sarif@v2.22.8 + with: + sarif_file: semgrep.sarif + + create-release: + name: Create release + needs: + - build-image + - init + permissions: + # Allow to create releases + contents: write + runs-on: ubuntu-22.04 + outputs: + RELEASE_ID: ${{ steps.create-release.outputs.result }} + # Only publish on non-scheduled main branch, as there is only one Helm repo and we cannot override an existing version + if: (github.event_name != 'schedule') && (github.ref == 'refs/heads/main') + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + + - name: Create release + id: create-release + uses: actions/github-script@v7.0.1 + with: + script: | + const isMain = context.ref == `refs/heads/${context.payload.repository.default_branch}`; + const repoName = context.repo.repo; + + console.log(isMain ? 'Creating release for default branch' : 'Creating release for non-default branch'); + + const { data } = await github.rest.repos.createRelease({ + draft: true, + generate_release_notes: true, + name: `${repoName} v${{ needs.init.outputs.VERSION }}`, + owner: context.repo.owner, + prerelease: !isMain, + repo: repoName, + tag_name: 'v${{ needs.init.outputs.VERSION }}', + target_commitish: context.ref, + }); + return data.id + + publish-release: + name: Publish release + permissions: + # Allow to write releases + contents: write + runs-on: ubuntu-22.04 + needs: + - create-release + - init + # Only publish on non-scheduled default branch + if: (github.event_name != 'schedule') && (github.ref == 'refs/heads/${context.payload.repository.default_branch}') + steps: + - name: publish release + id: publish-release + uses: actions/github-script@v7.0.1 + with: + script: | + github.rest.repos.updateRelease({ + draft: false, + owner: context.repo.owner, + release_id: ${{ needs.create-release.outputs.RELEASE_ID }}, + repo: context.repo.repo, + }); diff --git a/Dockerfile b/Dockerfile index f8541416..7db2a947 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,22 @@ # Base container FROM docker.io/library/python:3.11-slim-bullseye@sha256:9f35f3a6420693c209c11bba63dcf103d88e47ebe0b205336b5168c122967edf AS base +RUN rm -f /etc/apt/apt.conf.d/docker-clean \ + && echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache +RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \ + apt-get update -q + # Build container FROM base AS build RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked --mount=target=/root/.cache/pip,type=cache,sharing=locked \ - apt-get update \ - && apt-get install --yes gcc python3-dev \ - && python3 -m pip install --upgrade pip setuptools wheel + apt-get install -y -q --no-install-recommends \ + gcc \ + python3-dev \ + && python3 -m pip install --upgrade \ + pip \ + setuptools \ + wheel RUN python -m venv /venv ENV PATH=/venv/bin:$PATH @@ -33,4 +42,6 @@ ENV PATH=/venv/bin:$PATH COPY --chown=appuser:appuser . /app -CMD ["bash", "-c", "cd /app && uvicorn main:api --host 0.0.0.0 --port 8080 --proxy-headers --no-server-header --timeout-keep-alive 60 --header x-version:${VERSION}"] +WORKDIR /app + +CMD ["bash", "-c", "uvicorn main:api --host 0.0.0.0 --port 8080 --proxy-headers --no-server-header --timeout-keep-alive 60 --header x-version:${VERSION}"] diff --git a/Makefile b/Makefile index c154530a..2923ec0e 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ start: --no-server-header \ --port 8080 \ --proxy-headers \ + --timeout-keep-alive 60 \ --reload @@ -58,3 +59,14 @@ build: --tag $(container_name):$(version_small) \ --tag $(container_name):latest \ . + +run: + $(docker) run \ + --env EVENTS_DOMAIN=$(tunnel_url) \ + --env VERSION=$(version_full) \ + --mount type=bind,source="$(CURDIR)/.env",target="/app/.env" \ + --mount type=bind,source="$(CURDIR)/config.yaml",target="/app/config.yaml" \ + --name claim-ai-phone-bot \ + --publish 8080:8080 \ + --rm \ + $(container_name):$(version_small) diff --git a/README.md b/README.md index ab7e62a1..cc277ce7 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ graph user -- Call --> communication_service_call ``` -## Installation +## Local installation ### Prerequisites @@ -193,3 +193,10 @@ make tunnel # Start the local API server make start ``` + +## Remote deployment + +Container is available on GitHub Actions, at: + +- Latest version from a branch: `ghcr.io/clemlesne/claim-ai-phone-bot:main` +- Specific tag: `ghcr.io/clemlesne/claim-ai-phone-bot:0.1.0` (recommended)