diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 517c2f9c..26778e17 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ jobs: docker-push: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Build run: | docker build -t onsdigital/eq-questionnaire-validator:latest . diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 1a97926a..a4f0e6b7 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -7,15 +7,17 @@ on: jobs: lint: + permissions: + contents: read runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - run: | echo "PYTHON_VERSION=$(cat .python-version)" >> $GITHUB_ENV - - uses: actions/setup-python@v5 + - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: ${{ env.PYTHON_VERSION }} - - uses: actions/setup-node@v4 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version-file: ".nvmrc" cache: "npm" @@ -25,7 +27,7 @@ jobs: run: npm install - name: Install Poetry - uses: snok/install-poetry@v1 + uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a # v1.4.1 with: version: 1.3.2 virtualenvs-create: true @@ -33,7 +35,7 @@ jobs: virtualenvs-path: ~/.virtualenvs - name: Cache Poetry virtualenv - uses: actions/cache@v4 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 id: cache-virtualenv with: path: ~/.virtualenvs @@ -45,15 +47,17 @@ jobs: run: make lint test-unit: + permissions: + contents: read runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - run: echo "PYTHON_VERSION=$(cat .python-version)" >> $GITHUB_ENV - - uses: actions/setup-python@v5 + - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 with: python-version: ${{ env.PYTHON_VERSION }} - - uses: actions/setup-node@v4 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version-file: ".nvmrc" cache: "npm" @@ -65,7 +69,7 @@ jobs: run: make test-ajv - name: Install Poetry - uses: snok/install-poetry@v1 + uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a # v1.4.1 with: version: 1.3.2 virtualenvs-create: true @@ -73,7 +77,7 @@ jobs: virtualenvs-path: ~/.virtualenvs - name: Cache Poetry virtualenv - uses: actions/cache@v4 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 id: cache-virtualenv with: path: ~/.virtualenvs @@ -85,9 +89,11 @@ jobs: run: make test-unit docker-push: + permissions: + contents: read runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Tag run: | CLEAN_TAG=$(echo "${{ github.event.pull_request.head.ref }}" | tr / -) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 92646e48..fa297c48 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,13 +4,16 @@ on: release: types: [published] +permissions: + contents: read + jobs: docker-push: runs-on: ubuntu-22.04 env: TAG: ${{ github.event.release.tag_name }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Build run: | docker build -t onsdigital/eq-questionnaire-validator:$TAG . diff --git a/api.py b/api.py index 4dc9d69b..668892fe 100644 --- a/api.py +++ b/api.py @@ -2,6 +2,7 @@ import os from json import JSONDecodeError from urllib import error, request +from urllib.parse import urlparse import requests import uvicorn @@ -36,6 +37,20 @@ async def validate_schema_request_body(payload=Body(None)): async def validate_schema_from_url(url=None): if url: logger.info("Validating schema from URL", url=url) + allowed_domains = ["github.com", "gist.github.com"] + parsed_url = urlparse(url) + if parsed_url.hostname not in allowed_domains: + return Response( + status_code=400, + content=f"URL domain [{parsed_url.hostname}] is not allowed", + ) + if parsed_url.hostname == "github.com" and not parsed_url.path.startswith( + "/ONSdigital/" + ): + return Response( + status_code=400, + content="GitHub URLs must be from an ONSDigital repository", + ) try: with request.urlopen(url) as opened_url: return await validate_schema(data=opened_url.read().decode())