From df486df30ea6454b9f107a8a923990339f6ff8a6 Mon Sep 17 00:00:00 2001 From: Krishna Suravarapu <36037520+KrishnaSuravarapu@users.noreply.github.com> Date: Tue, 14 Jul 2026 16:43:54 +0530 Subject: [PATCH] security: container + CI hardening (F-012/013/014/015/016/017) - F-012 (CTO-4860): add .dockerignore excluding secrets/, *.env, config.json so credential files never enter the build context / image layers. - F-013 (CTO-4861): drop '-G sudo' from the app user in Dockerfile. - F-014 (CTO-4862): pin every GitHub Actions 'uses:' to a 40-char commit SHA. - F-015 (CTO-4863): add top-level 'permissions: contents: read' to the five workflows lacking one (semgrep already had it). - F-016 (CTO-4864): remove C_FORCE_ROOT=true from ops_app_celery.env and add no-new-privileges to the celery service (image already runs as USER app). - F-017 (CTO-4865): add no-new-privileges to web + celery (blast-radius). The dev source bind-mount itself is left for a separate dev/prod deploy decision. Co-Authored-By: Claude Opus 4.8 (1M context) --- .dockerignore | 28 ++++++++++++++++++++++++++ .github/workflows/commitlint.yml | 7 +++++-- .github/workflows/config-validator.yml | 5 ++++- .github/workflows/docker-push.yml | 15 ++++++++------ .github/workflows/pre-commit.yml | 5 ++++- .github/workflows/semgrep.yml | 2 +- .github/workflows/unit-tests.yml | 7 +++++-- Dockerfile | 2 +- docker-compose.yml | 4 ++++ secrets/ops_app_celery.env | 1 - 10 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..aea83715 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,28 @@ +# Keep secrets and local config out of the build context / image layers (F-012) +secrets/ +*.env +.env* +config.json + +# VCS / CI +.git/ +.github/ +.gitignore + +# Local bind-mount data — provided at runtime, never baked into the image +mounts/ + +# Python / build noise +__pycache__/ +*.py[cod] +*.egg-info/ +.pytest_cache/ +.coverage +htmlcov/ +.venv/ +venv/ + +# Editor / OS +.vscode/ +.idea/ +.DS_Store diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index 474a4668..22e6a715 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -1,10 +1,13 @@ name: Check Commit Messages with Commitlint on: [pull_request] +permissions: + contents: read + jobs: commitlint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 with: fetch-depth: 0 - - uses: wagoid/commitlint-github-action@v5 + - uses: wagoid/commitlint-github-action@9763196e10f27aef304c9b8b660d31d97fce0f99 # v5 diff --git a/.github/workflows/config-validator.yml b/.github/workflows/config-validator.yml index 85275665..21bd206a 100644 --- a/.github/workflows/config-validator.yml +++ b/.github/workflows/config-validator.yml @@ -1,10 +1,13 @@ # github action to run commit-msg hook on pull request commits and push commits to master branch name: Validate sample config on: pull_request +permissions: + contents: read + jobs: config-validator: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Run config-validator run: python scripts/validator.py config.json.sample diff --git a/.github/workflows/docker-push.yml b/.github/workflows/docker-push.yml index a4a36167..9035b9a8 100644 --- a/.github/workflows/docker-push.yml +++ b/.github/workflows/docker-push.yml @@ -4,19 +4,22 @@ on: tags: - v* +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@v3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2 - name: Docker metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4 with: images: | browserstack/enigma @@ -25,12 +28,12 @@ jobs: type=semver,pattern=v{{major}}.{{minor}} type=semver,pattern=v{{major}} - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@0a97817b6ade9f46837855d676c4cca3a2471fc9 # v4 with: context: . push: true diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 88b3f3a0..b9ced062 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,11 +1,14 @@ # github action to run commit-msg hook on pull request commits and push commits to master branch name: Pre Commit Hook on: [pull_request] +permissions: + contents: read + jobs: commit-msg-hook: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Run commit-msg hook run: | pip install pre-commit==2.21.0 diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index ea7e1eb3..9ee1dbc6 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -21,5 +21,5 @@ jobs: image: returntocorp/semgrep:1.166.0 if: (github.actor != 'dependabot[bot]') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - run: semgrep --error --config "p/cwe-top-25" --config "p/owasp-top-ten" --config "p/r2c-security-audit" diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 010c79a9..664b7ed2 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -1,5 +1,8 @@ name: Unit Tests and Lint on: [push] +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest @@ -7,9 +10,9 @@ jobs: matrix: python-version: ['3.9', '3.10', '3.11'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/Dockerfile b/Dockerfile index c3f01fba..33154505 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ RUN apt update && apt install -y netcat dnsutils libmariadb-dev RUN mkdir -p /ebs/logs && touch /ebs/logs/engima.log && chmod 777 /ebs/logs/engima.log ARG APPUID=1001 -RUN useradd -rm -d /home/app -s /bin/bash -g root -G sudo -u "$APPUID" app +RUN useradd -rm -d /home/app -s /bin/bash -g root -u "$APPUID" app WORKDIR /srv/code/dev RUN mkdir -p logs RUN mkdir -p db diff --git a/docker-compose.yml b/docker-compose.yml index abf63a91..48b49a17 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,8 @@ services: - ./mounts/logs:/ebs/logs ports: - 8000:8000 + security_opt: + - no-new-privileges:true depends_on: - db db: @@ -54,6 +56,8 @@ services: - ./mounts/logs:/ebs/logs env_file: - ./secrets/ops_app_celery.env + security_opt: + - no-new-privileges:true depends_on: - db - redis diff --git a/secrets/ops_app_celery.env b/secrets/ops_app_celery.env index 32b16087..e0c37afb 100644 --- a/secrets/ops_app_celery.env +++ b/secrets/ops_app_celery.env @@ -1,6 +1,5 @@ CELERY_BROKER_URL=redis://redis:6379 CELERY_RESULT_BACKEND=redis://redis:6379 -C_FORCE_ROOT=true MYSQL_ROOT_PASSWORD=testtest MYSQL_DATABASE=enigma MYSQL_ROOT_HOST=%