diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..7958e8b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @auth0/project-dx-sdks-engineer-codeowner diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml new file mode 100644 index 0000000..08a1663 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -0,0 +1,67 @@ +name: 🐞 Report a bug +description: Have you found a bug or issue? Create a bug report for this library +labels: ["bug"] + +body: + - type: markdown + attributes: + value: | + **Please do not report security vulnerabilities here**. The [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues. + + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: I have looked into the [Readme](https://github.com/auth0/auth0-fastapi-api#readme) and [Examples](https://github.com/auth0/auth0-fastapi-api/blob/master/EXAMPLES.md), and have not found a suitable solution or answer. + required: true + - label: I have looked into the [API documentation](https://auth0-fastapi-api.readthedocs.io/en/latest/) and have not found a suitable solution or answer. + required: true + - label: I have searched the [issues](https://github.com/auth0/auth0-fastapi-api/issues) and have not found a suitable solution or answer. + required: true + - label: I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer. + required: true + - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). + required: true + + - type: textarea + id: description + attributes: + label: Description + description: Provide a clear and concise description of the issue, including what you expected to happen. + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Reproduction + description: Detail the steps taken to reproduce this error, and whether this issue can be reproduced consistently or if it is intermittent. + placeholder: | + 1. Step 1... + 2. Step 2... + 3. ... + validations: + required: true + + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Other libraries that might be involved, or any other relevant information you think would be useful. + validations: + required: false + + - type: input + id: environment-version + attributes: + label: auth0-fastapi-api version + validations: + required: true + + - type: input + id: environment-python-version + attributes: + label: Python version + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/Feature Request.yml b/.github/ISSUE_TEMPLATE/Feature Request.yml new file mode 100644 index 0000000..923e979 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature Request.yml @@ -0,0 +1,53 @@ +name: 🧩 Feature request +description: Suggest an idea or a feature for this library +labels: ["feature request"] + +body: + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: I have looked into the [Readme](https://github.com/auth0/auth0-fastapi-api#readme) and [Examples](https://github.com/auth0/auth0-fastapi-api/blob/master/EXAMPLES.md), and have not found a suitable solution or answer. + required: true + - label: I have looked into the [API documentation](https://auth0-fastapi-api.readthedocs.io/en/latest/) and have not found a suitable solution or answer. + required: true + - label: I have searched the [issues](https://github.com/auth0/auth0-fastapi-api/issues) and have not found a suitable solution or answer. + required: true + - label: I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer. + required: true + - label: I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md). + required: true + + - type: textarea + id: description + attributes: + label: Describe the problem you'd like to have solved + description: A clear and concise description of what the problem is. + placeholder: I'm always frustrated when... + validations: + required: true + + - type: textarea + id: ideal-solution + attributes: + label: Describe the ideal solution + description: A clear and concise description of what you want to happen. + validations: + required: true + + - type: textarea + id: alternatives-and-workarounds + attributes: + label: Alternatives and current workarounds + description: A clear and concise description of any alternatives you've considered or any workarounds that are currently in place. + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..65c99a9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Auth0 Community + url: https://community.auth0.com + about: Discuss this SDK in the Auth0 Community forums diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..aa1a94f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,32 @@ +### Changes + +Please describe both what is changing and why this is important. Include: + +- Endpoints added, deleted, deprecated, or changed +- Classes and methods added, deleted, deprecated, or changed +- Screenshots of new or changed UI, if applicable +- A summary of usage if this is a new feature or change to a public API (this should also be added to relevant documentation once released) +- Any alternative designs or approaches considered + +### References + +Please include relevant links supporting this change such as a: + +- support ticket +- community post +- StackOverflow post +- support forum thread + +### Testing + +Please describe how this can be tested by reviewers. Be specific about anything not tested and reasons why. If this library has unit and/or integration testing, tests should be added for new functionality and existing tests should complete without errors. + +- [ ] This change adds unit test coverage +- [ ] This change adds integration test coverage +- [ ] This change has been tested on the latest version of the platform/language or why not + +### Checklist + +- [ ] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) +- [ ] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) +- [ ] All existing and new tests complete without errors diff --git a/.github/actions/get-prerelease/action.yml b/.github/actions/get-prerelease/action.yml new file mode 100644 index 0000000..131f93d --- /dev/null +++ b/.github/actions/get-prerelease/action.yml @@ -0,0 +1,30 @@ +name: Return a boolean indicating if the version contains prerelease identifiers + +# +# Returns a simple true/false boolean indicating whether the version indicates it's a prerelease or not. +# +# TODO: Remove once the common repo is public. +# + +inputs: + version: + required: true + +outputs: + prerelease: + value: ${{ steps.get_prerelease.outputs.PRERELEASE }} + +runs: + using: composite + + steps: + - id: get_prerelease + shell: bash + run: | + if [[ "${VERSION}" == *"beta"* || "${VERSION}" == *"alpha"* ]]; then + echo "PRERELEASE=true" >> $GITHUB_OUTPUT + else + echo "PRERELEASE=false" >> $GITHUB_OUTPUT + fi + env: + VERSION: ${{ inputs.version }} \ No newline at end of file diff --git a/.github/actions/get-release-notes/action.yml b/.github/actions/get-release-notes/action.yml new file mode 100644 index 0000000..62ea34e --- /dev/null +++ b/.github/actions/get-release-notes/action.yml @@ -0,0 +1,42 @@ +name: Return the release notes extracted from the PR body + +# +# Returns the release notes from the content of a pull request linked to a release branch. It expects the branch name to be in the format release/vX.Y.Z, release/X.Y.Z, release/vX.Y.Z-beta.N. etc. +# +# TODO: Remove once the common repo is public. +# +inputs: + version: + required: true + repo_name: + required: false + repo_owner: + required: true + token: + required: true + +outputs: + release-notes: + value: ${{ steps.get_release_notes.outputs.RELEASE_NOTES }} + +runs: + using: composite + + steps: + - uses: actions/github-script@v7 + id: get_release_notes + with: + result-encoding: string + script: | + const { data: pulls } = await github.rest.pulls.list({ + owner: process.env.REPO_OWNER, + repo: process.env.REPO_NAME, + state: 'all', + head: `${process.env.REPO_OWNER}:release/${process.env.VERSION}`, + }); + core.setOutput('RELEASE_NOTES', pulls[0]?.body ?? ''); + env: + GITHUB_TOKEN: ${{ inputs.token }} + REPO_OWNER: ${{ inputs.repo_owner }} + REPO_NAME: ${{ inputs.repo_name }} + VERSION: ${{ inputs.version }} \ No newline at end of file diff --git a/.github/actions/get-version/action.yml b/.github/actions/get-version/action.yml new file mode 100644 index 0000000..84814a3 --- /dev/null +++ b/.github/actions/get-version/action.yml @@ -0,0 +1,21 @@ +name: Return the version extracted from the branch name + +# +# Returns the version from the .version file. +# +# TODO: Remove once the common repo is public. +# + +outputs: + version: + value: ${{ steps.get_version.outputs.VERSION }} + +runs: + using: composite + + steps: + - id: get_version + shell: bash + run: | + VERSION=$(head -1 .version) + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT \ No newline at end of file diff --git a/.github/actions/release-create/action.yml b/.github/actions/release-create/action.yml new file mode 100644 index 0000000..a0db443 --- /dev/null +++ b/.github/actions/release-create/action.yml @@ -0,0 +1,47 @@ +name: Create a GitHub release + +# +# Creates a GitHub release with the given version. +# +# TODO: Remove once the common repo is public. +# + +inputs: + token: + required: true + files: + required: false + name: + required: true + body: + required: true + tag: + required: true + commit: + required: true + draft: + default: false + required: false + prerelease: + default: false + required: false + fail_on_unmatched_files: + default: true + required: false + +runs: + using: composite + + steps: + - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 + with: + body: ${{ inputs.body }} + name: ${{ inputs.name }} + tag_name: ${{ inputs.tag }} + target_commitish: ${{ inputs.commit }} + draft: ${{ inputs.draft }} + prerelease: ${{ inputs.prerelease }} + fail_on_unmatched_files: ${{ inputs.fail_on_unmatched_files }} + files: ${{ inputs.files }} + env: + GITHUB_TOKEN: ${{ inputs.token }} \ No newline at end of file diff --git a/.github/actions/rl-scanner/action.yml b/.github/actions/rl-scanner/action.yml new file mode 100644 index 0000000..7a2b774 --- /dev/null +++ b/.github/actions/rl-scanner/action.yml @@ -0,0 +1,71 @@ +name: "Reversing Labs Scanner" +description: "Runs the Reversing Labs scanner on a specified artifact." +inputs: + artifact-path: + description: "Path to the artifact to be scanned." + required: true + version: + description: "Version of the artifact." + required: true + +runs: + using: "composite" + steps: + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install Python dependencies + shell: bash + run: | + pip install boto3 requests + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: ${{ env.PRODSEC_TOOLS_ARN }} + aws-region: us-east-1 + mask-aws-account-id: true + + - name: Install RL Wrapper + shell: bash + run: | + pip install rl-wrapper>=1.0.6 --index-url "https://${{ env.PRODSEC_TOOLS_USER }}:${{ env.PRODSEC_TOOLS_TOKEN }}@a0us.jfrog.io/artifactory/api/pypi/python-local/simple" + + - name: Run RL Scanner + shell: bash + env: + RLSECURE_LICENSE: ${{ env.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ env.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ env.SIGNAL_HANDLER_TOKEN }} + PYTHONUNBUFFERED: 1 + run: | + if [ ! -f "${{ inputs.artifact-path }}" ]; then + echo "Artifact not found: ${{ inputs.artifact-path }}" + exit 1 + fi + + rl-wrapper \ + --artifact "${{ inputs.artifact-path }}" \ + --name "${{ github.event.repository.name }}" \ + --version "${{ inputs.version }}" \ + --repository "${{ github.repository }}" \ + --commit "${{ github.sha }}" \ + --build-env "github_actions" \ + --suppress_output + + # Check the outcome of the scanner + if [ $? -ne 0 ]; then + echo "RL Scanner failed." + echo "scan-status=failed" >> $GITHUB_ENV + exit 1 + else + echo "RL Scanner passed." + echo "scan-status=success" >> $GITHUB_ENV + fi + +outputs: + scan-status: + description: "The outcome of the scan process." + value: ${{ env.scan-status }} diff --git a/.github/actions/tag-exists/action.yml b/.github/actions/tag-exists/action.yml new file mode 100644 index 0000000..b8f33f6 --- /dev/null +++ b/.github/actions/tag-exists/action.yml @@ -0,0 +1,36 @@ +name: Return a boolean indicating if a tag already exists for the repository + +# +# Returns a simple true/false boolean indicating whether the tag exists or not. +# +# TODO: Remove once the common repo is public. +# + +inputs: + token: + required: true + tag: + required: true + +outputs: + exists: + description: 'Whether the tag exists or not' + value: ${{ steps.tag-exists.outputs.EXISTS }} + +runs: + using: composite + + steps: + - id: tag-exists + shell: bash + run: | + GET_API_URL="https://api.github.com/repos/${GITHUB_REPOSITORY}/git/ref/tags/${TAG_NAME}" + http_status_code=$(curl -LI $GET_API_URL -o /dev/null -w '%{http_code}\n' -s -H "Authorization: token ${GITHUB_TOKEN}") + if [ "$http_status_code" -ne "404" ] ; then + echo "EXISTS=true" >> $GITHUB_OUTPUT + else + echo "EXISTS=false" >> $GITHUB_OUTPUT + fi + env: + TAG_NAME: ${{ inputs.tag }} + GITHUB_TOKEN: ${{ inputs.token }} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6e7f8d4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..3cc35f1 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,20 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 90 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +daysUntilClose: 7 + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: [] + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: true + +# Label to use when marking as stale +staleLabel: closed:stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇♂️ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..94783bf --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,53 @@ +name: CodeQL + +on: + merge_group: + pull_request: + types: + - opened + - synchronize + push: + branches: + - main + schedule: + - cron: "56 12 * * 1" + +permissions: + actions: read + contents: read + security-events: write + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + analyze: + name: Check for Vulnerabilities + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [python] + + steps: + - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' + run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection. + + - name: Checkout + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + queries: +security-and-quality + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..96a410f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,59 @@ +name: Build Documentation + +on: + push: + branches: + - main + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "documentation" + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Configure Python + uses: actions/setup-python@v5 + with: + python-version: "3.8" + + - name: Configure dependencies + run: | + pip install --user --upgrade pip + pip install --user pipx + pipx ensurepath + pipx install sphinx==5.3.0 + pipx inject sphinx pyjwt cryptography sphinx-mdinclude sphinx-rtd-theme sphinx-autodoc-typehints + + - name: Build documentation + run: | + sphinx-build ./docs/source ./docs/build --keep-going -n -a -b html + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: "./docs/build" + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: "github-pages" + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - id: deployment + name: Deploy to GitHub Pages + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..19c0283 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,90 @@ +name: Publish Release + +on: + workflow_dispatch: + +### TODO: Replace instances of './.github/actions/' with reference to the `dx-sdk-actions` repo is made public and this file is transferred over +### TODO: Also remove `get-prerelease`, `get-version`, `release-create`, `tag-create` and `tag-exists` actions from this repo's .github/actions folder once the repo is public. + +permissions: + contents: write + id-token: write # Required for trusted publishing to PyPI + +jobs: + rl-scanner: + uses: ./.github/workflows/rl-scanner.yml + with: + python-version: "3.10" + artifact-name: "auth0-fastapi-api.tgz" + secrets: + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} + publish-pypi: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) + name: "PyPI" + runs-on: ubuntu-latest + # needs: rl-scanner + environment: release + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + # Get the version from the branch name + - id: get_version + uses: ./.github/actions/get-version + + # Get the prerelease flag from the branch name + - id: get_prerelease + uses: ./.github/actions/get-prerelease + with: + version: ${{ steps.get_version.outputs.version }} + + # Get the release notes + # This will expose the release notes as env.RELEASE_NOTES + - id: get_release_notes + uses: ./.github/actions/get-release-notes + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: ${{ steps.get_version.outputs.version }} + repo_owner: ${{ github.repository_owner }} + repo_name: ${{ github.event.repository.name }} + + # Create a release for the tag + - uses: ./.github/actions/release-create + with: + token: ${{ secrets.GITHUB_TOKEN }} + name: ${{ steps.get_version.outputs.version }} + body: ${{ steps.get_release_notes.outputs.release-notes }} + tag: ${{ steps.get_version.outputs.version }} + commit: ${{ github.sha }} + prerelease: ${{ steps.get_prerelease.outputs.prerelease }} + + - name: Configure Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Configure dependencies + run: | + pip install --user --upgrade pip + pip install --user pipx + pipx ensurepath + pipx install poetry + poetry config virtualenvs.in-project true + poetry install --with dev + poetry self add "poetry-dynamic-versioning[plugin]" + + - name: Build release + run: | + poetry build + + - name: Publish release + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/rl-scanner.yml b/.github/workflows/rl-scanner.yml new file mode 100644 index 0000000..a10b241 --- /dev/null +++ b/.github/workflows/rl-scanner.yml @@ -0,0 +1,83 @@ +name: RL-Secure Workflow + +on: + workflow_call: + inputs: + python-version: + required: true + type: string + artifact-name: + required: true + type: string + secrets: + RLSECURE_LICENSE: + required: true + RLSECURE_SITE_KEY: + required: true + SIGNAL_HANDLER_TOKEN: + required: true + PRODSEC_TOOLS_USER: + required: true + PRODSEC_TOOLS_TOKEN: + required: true + PRODSEC_TOOLS_ARN: + required: true + +jobs: + rl-scanner: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) + runs-on: ubuntu-latest + outputs: + scan-status: ${{ steps.rl-scan-conclusion.outcome }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Configure Python + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python-version }} + + - name: Configure dependencies + run: | + pip install --user --upgrade pip + pip install --user pipx + pipx ensurepath + pipx install poetry==1.4.2 + pip install --upgrade pip + pip install boto3 requests + poetry config virtualenvs.in-project true + poetry install --with dev + poetry self add "poetry-dynamic-versioning[plugin]==1.1.1" + + - name: Build release + run: | + poetry build + + - name: Create tgz build artifact + run: | + tar -czvf ${{ inputs.artifact-name }} * + + - name: Get Artifact Version + id: get_version + uses: ./.github/actions/get-version + + - name: Run RL Scanner + id: rl-scan-conclusion + uses: ./.github/actions/rl-scanner + with: + artifact-path: "$(pwd)/${{ inputs.artifact-name }}" + version: "${{ steps.get_version.outputs.version }}" + env: + RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }} + RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }} + SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }} + PRODSEC_TOOLS_USER: ${{ secrets.PRODSEC_TOOLS_USER }} + PRODSEC_TOOLS_TOKEN: ${{ secrets.PRODSEC_TOOLS_TOKEN }} + PRODSEC_TOOLS_ARN: ${{ secrets.PRODSEC_TOOLS_ARN }} + + - name: Output scan result + run: echo "scan-status=${{ steps.rl-scan-conclusion.outcome }}" >> $GITHUB_ENV diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml new file mode 100644 index 0000000..7913b13 --- /dev/null +++ b/.github/workflows/semgrep.yml @@ -0,0 +1,40 @@ +name: Semgrep + +on: + merge_group: + pull_request: + types: + - opened + - synchronize + push: + branches: + - main + schedule: + - cron: "30 0 1,15 * *" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + run: + name: Check for Vulnerabilities + runs-on: ubuntu-latest + + container: + image: returntocorp/semgrep + + steps: + - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' + run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection. + + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.ref }} + + - run: semgrep ci + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml new file mode 100644 index 0000000..090b428 --- /dev/null +++ b/.github/workflows/snyk.yml @@ -0,0 +1,40 @@ +name: Snyk + +on: + merge_group: + workflow_dispatch: + pull_request: + types: + - opened + - synchronize + push: + branches: + - main + schedule: + - cron: '30 0 1,15 * *' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + + check: + + name: Check for Vulnerabilities + runs-on: ubuntu-latest + + steps: + - if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group' + run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection. + + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.ref }} + + - uses: snyk/actions/python@b98d498629f1c368650224d6d212bf7dfa89e4bf # pin@0.4.0 + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..22fefd4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,85 @@ +name: Build and Test + +on: + merge_group: + pull_request: + types: + - opened + - synchronize + push: + branches: + - main + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + run: + name: Run + runs-on: ubuntu-latest + + env: + BUBBLEWRAP_ARGUMENTS: | + --unshare-all \ + --clearenv \ + --ro-bind / / \ + --bind ${{ github.workspace }} ${{ github.workspace }} \ + --tmpfs $HOME \ + --tmpfs /tmp \ + --tmpfs /var \ + --dev /dev \ + --proc /proc \ + --die-with-parent \ + --new-session \ + + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.ref }} + + - name: Configure Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: "${{ matrix.python-version }}" + + - name: Configure dependencies + run: | + sudo apt install bubblewrap + pip install --user --upgrade pip + pip install --user pipx + pip install --user setuptools + pipx ensurepath + pipx install poetry + poetry config virtualenvs.in-project true + poetry install --with dev + poetry self add "poetry-dynamic-versioning[plugin]" + + - name: Run tests + run: | + poetry run pytest + + # - name: Run lint + # run: | + # pipx install black==23.3.0 + # pipx install flake8==5.0.4 + # pipx install isort==5.11.5 + # pipx install pyupgrade==3.3.2 + # black . --check + # flake8 . --count --show-source --statistics + # isort . --diff --profile black + # pyupgrade . --py37-plus --keep-runtime-typing + + - if: ${{ matrix.python-version == '3.10' }} + name: Upload coverage + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # pin@5.4.3 + with: + token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file diff --git a/.shiprc b/.shiprc new file mode 100644 index 0000000..ce24dbd --- /dev/null +++ b/.shiprc @@ -0,0 +1,6 @@ +{ + "files": { + ".version": [] + }, + "prefixVersion": false +} diff --git a/.snyk b/.snyk new file mode 100644 index 0000000..020fe3c --- /dev/null +++ b/.snyk @@ -0,0 +1,20 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.12.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-PYTHON-REQUESTS-72435: + - '*': + reason: 'unaffected, only affects https->http authorization header redirection.' + expires: 2019-11-05T00:00:00.000Z + SNYK-PYTHON-REQUESTS-40470: + - '*': + reason: 'patched in latest python versions: https://bugs.python.org/issue27568' + "snyk:lic:pip:certifi:MPL-2.0": + - '*': + reason: "Accepting certifi’s MPL-2.0 license for now" + expires: "2030-12-31T23:59:59Z" + "snyk:lic:pip:jwcrypto:LGPL-3.0": + - '*': + reason: "Accepting jwcrypto’s LGPL-3.0 license for now" + expires: "2030-12-31T23:59:59Z" +patch: {} diff --git a/.version b/.version new file mode 100644 index 0000000..1943259 --- /dev/null +++ b/.version @@ -0,0 +1 @@ +1.0.0b3 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..62210c4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contribution + +Please read [Auth0's contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md). + +## Environment setup + +- Make sure you have node and npm installed +- Run `poetry install` to install dependencies +- Follow the local development steps below to get started + +## Local development + +- `poetry install`: install dependencies +- `poetry run pytest`: run unit tests +- `poetry build`: compile the package + +## Testing + +### Adding tests + +Every change should be accompanied by a test. + +### Running tests + +Run unit tests before opening a PR: + +```bash +poetry run pytest +``` + +Also include any information about essential manual tests. \ No newline at end of file diff --git a/README.md b/README.md index 39cac01..5261276 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -The Auth0 FastAPI API SDK library allows you to secure FastAPI APIs using bearer tokens from Auth0. - -It exposes a simple require_auth dependency that checks if incoming requests have a valid JWT, then provides the token claims to your route handler. +   [](https://opensource.org/licenses/MIT) @@ -144,7 +142,7 @@ We appreciate feedback and contribution to this repo! Before you get started, pl - [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md) - [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md) -- [This repo's contribution guide](./../../CONTRIBUTING.md) +- [This repo's contribution guide](https://github.com/auth0/auth0-fastapi-api/CONTRIBUTING.md) ### Raise an issue @@ -167,5 +165,5 @@ Please do not report security vulnerabilities on the public GitHub issue tracker Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?
- This project is licensed under the MIT license. See the LICENSE file for more info. + This project is licensed under the MIT license. See the LICENSE file for more info.
diff --git a/poetry.lock b/poetry.lock index c19ec61..08503b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -37,14 +37,14 @@ trio = ["trio (>=0.26.1)"] [[package]] name = "auth0-api-python" -version = "1.0.0b2" +version = "1.0.0b3" description = "SDK for verifying access tokens and securing APIs with Auth0, using Authlib." optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "auth0_api_python-1.0.0b2-py3-none-any.whl", hash = "sha256:3e1bb0363b0833852d96cf438316cca728afdefbc6b597385cb3fda6f33eb4bf"}, - {file = "auth0_api_python-1.0.0b2.tar.gz", hash = "sha256:380a92f407c2517463222a2d3bc9b51a0380148bfb4c3ff9dd99de98b03f64dc"}, + {file = "auth0_api_python-1.0.0b3-py3-none-any.whl", hash = "sha256:b85325d416ac027b36b2ea3eb64e440e2986460b3ec8c88163724ce29ebe4735"}, + {file = "auth0_api_python-1.0.0b3.tar.gz", hash = "sha256:c437ba001768a124a3742294b853a0d751fe68a1a77c2ee7901ef0dd0c921e8b"}, ] [package.dependencies] @@ -1414,4 +1414,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.9" -content-hash = "aec7b3233e9a61e9fd7b917ebd5efed2e678f5ec1d56d3233859c53b0d3e9086" +content-hash = "f69f90a4e6a7029a0858e1c510a18ec4b248d66d9c1e7de85b2652250fa15366" diff --git a/pyproject.toml b/pyproject.toml index e521d8e..7548619 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ python = "^3.9" fastapi = "^0.115.11" httpx = "^0.28.1" uvicorn = "^0.34.0" -auth0-api-python = ">=1.0.0b1" +auth0-api-python = ">=1.0.0b3" [tool.poetry.group.dev.dependencies] pytest = "^8.0" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..efcd6c2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,54 @@ +annotated-types==0.7.0 +anyio==4.9.0 +auth0-api-python==1.0.0b2 +Authlib==1.5.2 +backports.tarfile==1.2.0 +certifi==2025.4.26 +cffi==1.17.1 +charset-normalizer==3.4.1 +click==8.1.8 +coverage==7.8.0 +cryptography==44.0.1 +docutils==0.21.2 +exceptiongroup==1.2.2 +fastapi==0.115.12 +h11==0.16.0 +httpcore==1.0.9 +httpx==0.28.1 +id==1.5.0 +idna==3.10 +importlib_metadata==8.7.0 +iniconfig==2.1.0 +jaraco.classes==3.4.0 +jaraco.context==6.0.1 +jaraco.functools==4.1.0 +keyring==25.6.0 +markdown-it-py==3.0.0 +mdurl==0.1.2 +more-itertools==10.7.0 +nh3==0.2.21 +packaging==25.0 +pluggy==1.5.0 +pycparser==2.22 +pydantic==2.11.3 +pydantic_core==2.33.1 +Pygments==2.19.1 +pytest==8.3.5 +pytest-asyncio==0.20.3 +pytest-cov==4.1.0 +pytest-httpx==0.35.0 +pytest-mock==3.14.0 +readme_renderer==44.0 +requests==2.32.4 +requests-toolbelt==1.0.0 +rfc3986==2.0.0 +rich==14.0.0 +sniffio==1.3.1 +starlette==0.46.2 +tomli==2.2.1 +twine==6.1.0 +typing-inspection==0.4.0 +typing_extensions==4.13.2 +urllib3==2.4.0 +uvicorn==0.34.2 +zipp==3.21.0