diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 03ed08c..3816748 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -7,10 +7,17 @@ RUN apk add --no-cache bash git \ # Setup default user ARG USERNAME=vscode ARG USER_UID=1000 -ARG USER_GID=$USER_UID +ARG USER_GID=${USER_UID} -RUN addgroup -g $USER_GID -S $USERNAME && \ - adduser -u $USER_UID -S -G $USERNAME -s /bin/bash $USERNAME +RUN addgroup -g ${USER_GID} -S ${USERNAME} && \ + adduser -u ${USER_UID} -S -G ${USERNAME} -s /bin/bash ${USERNAME} # Switch to the default user -USER $USERNAME +USER ${USERNAME} + +# Set environment variables for pip +ENV PATH="/home/${USERNAME}/.local/bin:$PATH" \ + PIP_BREAK_SYSTEM_PACKAGES=1 \ + PIP_DISABLE_PIP_VERSION_CHECK=1 \ + PIP_NO_CACHE_DIR=1 \ + PYTHONUNBUFFERED=1 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f36c256..35744fd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,13 +7,14 @@ }, "vscode": { "extensions": [ + "gruntfuggly.triggertaskonsave", "ms-python.black-formatter", "ms-python.python", - "ms-python.isort", - "emeraldwalk.RunOnSave" + "ms-python.isort" ] } }, - "postStartCommand": "pip3 --disable-pip-version-check --no-cache-dir install -r requirements.txt --break-system-packages && python3 -m pytest tests", + "postStartCommand": "pip3 install --user -r requirements.txt", + "postAttachCommand": "python3 -m pytest tests", "remoteUser": "vscode" } diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml new file mode 100644 index 0000000..f0fab08 --- /dev/null +++ b/.github/workflows/draft-release.yml @@ -0,0 +1,84 @@ +name: Create a Draft Release + +permissions: + contents: write + +on: + push: + branches: + - main + workflow_dispatch: + +env: + TRIGGER_BRANCH: main + FILE_FILTER_PATTERN: '^(?!tests/).*\.py$' + +jobs: + create-release-draft: + runs-on: ubuntu-latest + + steps: + - name: Checkout code and fetch tags + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for modified matching files + id: check_changes + run: | + echo "Trigger branch: $TRIGGER_BRANCH" + echo "File filter pattern: $FILE_FILTER_PATTERN" + + git fetch origin "$TRIGGER_BRANCH" --depth=2 + MODIFIED=$(git diff --name-only HEAD^ HEAD) + + echo "Modified files:" + echo "$MODIFIED" + + MATCHING=$(echo "$MODIFIED" | grep -E "$FILE_FILTER_PATTERN" || true) + + echo "Matching files:" + echo "$MATCHING" + + if [[ -n "$MATCHING" ]]; then + echo "should_trigger=true" >> "$GITHUB_OUTPUT" + else + echo "should_trigger=false" >> "$GITHUB_OUTPUT" + fi + + - name: Determine next tag version + id: version + run: | + LATEST=$(git tag --sort=-v:refname | head -n 1) + echo "Latest tag: $LATEST" + + if [[ -z "$LATEST" ]]; then + NEXT_TAG="v0.0.1" + else + [[ "$LATEST" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)(-.+)?$ ]] + MAJOR=${BASH_REMATCH[1]} + MINOR=${BASH_REMATCH[2]} + PATCH=${BASH_REMATCH[3]} + SUFFIX=${BASH_REMATCH[4]} + MINOR=$((MINOR + 1)) + NEXT_TAG="v$MAJOR.$MINOR.$PATCH$SUFFIX" + fi + + echo "Next tag: $NEXT_TAG" + echo "tag=$NEXT_TAG" >> "$GITHUB_OUTPUT" + + - name: Create draft release + if: steps.check_changes.outputs.should_trigger == 'true' + run: | + curl -X POST \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/releases \ + -d '{ + "tag_name": "${{ steps.version.outputs.tag }}", + "target_commitish": "'"$TRIGGER_BRANCH"'", + "name": "${{ steps.version.outputs.tag }}", + "draft": true, + "prerelease": false, + "generate_release_notes": true + }' diff --git a/.github/workflows/pip-audit.yml b/.github/workflows/pip-audit.yml new file mode 100644 index 0000000..27f9f6d --- /dev/null +++ b/.github/workflows/pip-audit.yml @@ -0,0 +1,35 @@ +name: Python Dependencies Audit + +permissions: + contents: read + +on: + push: + paths: + - requirements.txt + pull_request: + paths: + - requirements.txt + schedule: + - cron: "0 4 * * 1" # Every Monday at 4:00 UTC + workflow_dispatch: + +jobs: + pip-audit: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pip-audit + + - name: Run pip-audit + run: pip-audit -r requirements.txt diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 767abfb..2e79288 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -1,13 +1,14 @@ name: Pytest CI +permissions: + contents: read + on: push: branches: - main pull_request: -permissions: {} - jobs: test: name: Pytest on ${{ matrix.os }} with Python ${{ matrix.python-version }} diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index 877dc78..90a7106 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -1,14 +1,14 @@ ---- name: Lint +permissions: + contents: read + on: push: branches: - main pull_request: null -permissions: {} - jobs: build: name: Lint diff --git a/.gitignore b/.gitignore index 5a44d50..1c5f543 100644 --- a/.gitignore +++ b/.gitignore @@ -122,9 +122,3 @@ dmypy.json # Cython debug symbols cython_debug/ - -# VS Code -.vscode/* - -# Except this specific file -!.vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 9f40579..4ed7278 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,13 +23,13 @@ "--profile", "black" ], - "emeraldwalk.runonsave": { - "commands": [ - { - "match": "tests[/\\\\](.*[/\\\\])?test_.*\\.py$", - "cmd": "python3 -m pytest '${relativeFile}' -v", - "autoShowOutputPanel": "error" - } + "triggerTaskOnSave.tasks": { + "Run on test file": [ + "tests/**/test_*.py" + ], + "Run all tests": [ + "!tests/**", + "**/*.py" ] }, "python.testing.pytestArgs": [ diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..040c119 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,30 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Run all tests", + "type": "shell", + "command": "python3 -m pytest tests", + "group": { + "kind": "test", + "isDefault": true + }, + "problemMatcher": [], + "runOptions": { + "runOn": "default" + } + }, + { + "label": "Run on test file", + "type": "shell", + "command": "python3 -m pytest '${relativeFile}' -v -x", + "group": { + "kind": "test" + }, + "problemMatcher": [], + "runOptions": { + "runOn": "default" + } + } + ] +} diff --git a/requirements.txt b/requirements.txt index b54e6b7..f09f886 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,10 @@ argon2-cffi>=23.1.0 -cryptography>=44.0.2 -Flask>=3.0.3 -Flask-JWT-Extended>=2.8.0 -Flask-Limiter>=3.7.0 -flask-cors>=4.0.1 +cryptography>=45.0.2 +Flask>=3.1.1 +Flask-JWT-Extended>=4.7.1 +Flask-Limiter>=3.12.0 +flask-cors>=6.0.0 PyMySQL>=1.1.1 -requests>=2.32.3 -waitress>=3.0.0 pytest>=8.3.5 -python-dotenv>=1.0.1 +python-dotenv>=1.1.0 +requests>=2.32.3