diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml deleted file mode 100644 index 2f279a1..0000000 --- a/.builds/freebsd.yml +++ /dev/null @@ -1,36 +0,0 @@ -image: freebsd/12.x -packages: - - python39 - - py39-sqlite3 - - jpeg-turbo - - py37-ansible -sources: - - https://git.sr.ht/~crocmagnon/blog -secrets: - - ea931da1-9acd-47b0-b6c9-52b8b61c4647 # Ansible hosts file - - 5c948915-48c2-4542-8fc1-a5676f4d7126 # Deploy SSH key -environment: - POETRY_VERSION: 1.1.4 -tasks: - - install_poetry: | - mkdir $HOME/bin - ln -s $(which python3.9) $HOME/bin/python - python -m ensurepip - python -m pip install poetry==$POETRY_VERSION - - install_deps: | - cd blog - python -m poetry install -n - - test: | - cd blog - python -m poetry run ./docker/runtests.sh - - check-branch: | - cd blog - if [ "$(git rev-parse master)" != "$(git rev-parse HEAD)" ]; then \ - complete-build; \ - fi - - deploy: | - ansible-playbook -i ~/ansiblehosts --ssh-common-args "-o StrictHostKeyChecking=no" blog/ansible/playbook.yml -triggers: - - action: email - condition: failure - to: Gabriel Augendre diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..cfcfdf9 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,83 @@ +stages: + - build + - test + - publish + - deploy + +variables: + # Can't compose variables with user-defined ones, so we repeat ourselves :'( + # See https://gitlab.com/gitlab-org/gitlab-runner/-/issues/1809 + IMAGE_REGISTRY: rg.fr-par.scw.cloud/crocmagnon + IMAGE_TESTS: $CI_REGISTRY_IMAGE:tests-latest + IMAGE_DEPS_TESTS: $CI_REGISTRY_IMAGE:tests-deps + IMAGE_LATEST: rg.fr-par.scw.cloud/crocmagnon/blog:latest + IMAGE_DEPS_LATEST: $CI_REGISTRY_IMAGE:deps + + PRE_COMMIT_IMAGE: rg.fr-par.scw.cloud/crocmagnon/pre-commit:latest + +.build: &build + script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $IMAGE_REGISTRY + - docker pull $IMAGE || true + - docker pull $DEPS || true + # Build this first stage separately so that we can cache it + - docker build --pull --build-arg POETRY_OPTIONS --target venv --cache-from $DEPS -t $DEPS . + # Build the final image. The "cache from" deps is necessary to take advantage of the intermediate image cache. + # See https://stackoverflow.com/a/52649913/2758732 and https://github.com/moby/moby/issues/34715 + - docker build --pull --build-arg POETRY_OPTIONS --cache-from $IMAGE --cache-from $DEPS -t $IMAGE . + - docker push $IMAGE + - docker push $DEPS + +build-tests: + <<: *build + stage: build + variables: + POETRY_OPTIONS: "" + before_script: + - export IMAGE=$IMAGE_TESTS + - export DEPS=$IMAGE_DEPS_TESTS + +.tests: &tests + stage: test + image: $IMAGE_TESTS + +unit_tests: + <<: *tests + script: + - cd /app + - python -m pytest + +pre_commit: + stage: test + image: $PRE_COMMIT_IMAGE + script: + - pre-commit run --all-files --color always --show-diff-on-failure + +missing_migrations: + <<: *tests + script: + - cd /app + - python manage.py makemigrations --check + +publish: + <<: *build + stage: publish + variables: + GIT_STRATEGY: none + POETRY_OPTIONS: "--no-dev" + before_script: + - export IMAGE=$IMAGE_LATEST + - export DEPS=$IMAGE_DEPS_LATEST + only: + - master + +#deploy: +# tags: +# - it4nw +# stage: deploy +# image: tobedefined # todo: look for image with ssh +# script: +# - exit 1 +# only: +# - master diff --git a/Dockerfile b/Dockerfile index baacc9c..91de9dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,22 +2,20 @@ FROM python:3.8.6-buster AS venv # https://python-poetry.org/docs/#installation -ENV POETRY_VERSION=1.0.10 +ENV POETRY_VERSION=1.1.4 RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python ENV PATH /root/.poetry/bin:$PATH ENV PYTHONPATH $PYTHONPATH:/root/.poetry/lib +ARG POETRY_OPTIONS WORKDIR /app COPY pyproject.toml poetry.lock ./ -# Will install dev deps as well, so that we can run tests in this image + RUN python -m venv --copies /app/venv \ && . /app/venv/bin/activate \ && poetry config cache-dir /app/poetry-cache \ - && (python -c "from poetry.factory import Factory; l = Factory().create_poetry('.').locker; exit(0) if l.is_locked() and l.is_fresh() else exit(1)" \ - && echo "poetry.lock is up to date") \ - || (>&2 echo "poetry.lock is outdated. Run `poetry lock` on your machine and commit the file." && exit 1) \ - && poetry install + && poetry install $POETRY_OPTIONS ## Get git versions diff --git a/ansible/blog.service b/ansible/blog.service deleted file mode 100644 index 3b14d15..0000000 --- a/ansible/blog.service +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -# PROVIDE: blog -# REQUIRE: LOGIN NETWORKING -# KEYWORD: shutdown - -. /etc/rc.subr - -name=blog -rcvar="blog_enable" - -load_rc_config $name -: ${blog_enable="NO"} -: ${blog_listen_addr="127.0.0.1:8000"} - -pidfile="/var/run/${name}.pid" -logfile="/var/log/${name}.log" - -blog_env_file="/srv/blog/.env" -command_interpreter="/srv/blogvenv/bin/python" -command="/srv/blogvenv/bin/gunicorn" -blog_flags="-D --chdir /srv/blog -b ${blog_listen_addr} --log-file ${logfile} --pid ${pidfile}" -command_args="blog.wsgi" - -start_precmd="${name}_prestart" -blog_prestart() -{ - . /srv/blog/.env - yes yes | /srv/blogvenv/bin/python /srv/blog/manage.py migrate - /srv/blogvenv/bin/python /srv/blog/manage.py collectstatic --noinput --clear - /srv/blogvenv/bin/python /srv/blog/manage.py assets build --manifest django -} - -run_rc_command "$1" diff --git a/ansible/hosts b/ansible/hosts deleted file mode 100644 index c9c9e35..0000000 --- a/ansible/hosts +++ /dev/null @@ -1 +0,0 @@ -blognas ansible_host=192.168.0.54 ansible_port=22 ansible_python_interpreter=/usr/local/bin/python diff --git a/ansible/nginx.conf b/ansible/nginx.conf deleted file mode 100644 index cb1225e..0000000 --- a/ansible/nginx.conf +++ /dev/null @@ -1,59 +0,0 @@ -worker_processes 1; - -events { - worker_connections 1024; -} - -http { - include mime.types; - default_type application/octet-stream; - - sendfile on; - keepalive_timeout 65; - - server { - server_name localhost:80; - - client_max_body_size 10M; - - gzip on; - gzip_types - application/javascript - application/x-javascript - application/json - application/rss+xml - application/xml - image/svg+xml - image/x-icon - application/vnd.ms-fontobject - application/font-sfnt - text/css - text/plain; - gzip_min_length 256; - gzip_comp_level 5; - gzip_http_version 1.1; - gzip_vary on; - - location /static/ { - alias /srv/blog/staticfiles/; - expires 30d; - } - - location /media/ { - alias /srv/blog/media/; - expires 30d; - } - - location / { - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto https; - proxy_pass http://localhost:8000; - proxy_redirect off; - } - - listen [::]:80; - listen 80; - } -} diff --git a/ansible/playbook.yml b/ansible/playbook.yml deleted file mode 100644 index bf4dd61..0000000 --- a/ansible/playbook.yml +++ /dev/null @@ -1,73 +0,0 @@ ---- -- name: deploy blog - hosts: blognas - remote_user: root - - tasks: - - name: install system dependencies - pkgng: - name: git,python39,py39-sqlite3,jpeg-turbo,nginx,curl,vim - - name: make python3.9 default - file: - path: /usr/local/bin/python3 - src: /usr/local/bin/python3.9 - state: link - - name: install pip - shell: - cmd: python -m ensurepip - creates: /usr/local/lib/python3.9/site-packages/pip - - name: fetch code - git: - repo: https://git.sr.ht/~crocmagnon/blog - dest: /srv/blog - force: yes - - name: create venv - shell: - cmd: python -m venv /srv/blogvenv - creates: /srv/blogvenv/bin/python - - name: install poetry - shell: - cmd: . /srv/blogvenv/bin/activate && python -m pip install poetry==1.1.4 - creates: /srv/blogvenv/bin/poetry - - name: install python dependencies - shell: - chdir: /srv/blog - cmd: . /srv/blogvenv/bin/activate && python -m poetry install --no-dev - - name: install service - copy: - remote_src: yes - src: /srv/blog/ansible/blog.service - dest: /usr/local/etc/rc.d/blog - owner: root - group: wheel - mode: 0755 - - name: enable and restart blog service - service: - name: blog - state: restarted - enabled: yes - - name: backup old nginx conf - copy: - remote_src: yes - src: /usr/local/etc/nginx/nginx.conf - dest: /usr/local/etc/nginx/nginx.conf.BKP - - name: install nginx conf - copy: - remote_src: yes - src: /srv/blog/ansible/nginx.conf - dest: /usr/local/etc/nginx/nginx.conf - owner: root - group: wheel - mode: 0644 - notify: - - restart nginx - - name: enable nginx service - service: - name: nginx - state: started - enabled: yes - handlers: - - name: restart nginx - service: - name: nginx - state: restarted diff --git a/docker/nginx.conf b/docker/nginx.conf index 02227b5..8177943 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -10,10 +10,12 @@ server { application/json application/rss+xml application/xml - image/svg+xml - image/x-icon application/vnd.ms-fontobject application/font-sfnt + image/svg+xml + image/x-icon + text/xml + text/javascript text/css text/plain; gzip_min_length 256; @@ -40,7 +42,9 @@ server { proxy_redirect off; } - add_header Content-Security-Policy "frame-ancestors 'none'; default-src 'none'; img-src https:; script-src 'self' https://plausible.augendre.info; connect-src https://plausible.augendre.info; style-src 'self' 'unsafe-inline'; font-src 'self'" always; + add_header Content-Security-Policy "frame-ancestors 'none'; default-src 'none'; img-src https:; script-src 'self' + https://plausible.augendre.info; connect-src https://plausible.augendre.info; style-src 'self' 'unsafe-inline'; + font-src 'self'; manifest-src 'self';" always; add_header X-Frame-Options "DENY" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; diff --git a/pre-commit.Dockerfile b/pre-commit.Dockerfile new file mode 100644 index 0000000..f9833da --- /dev/null +++ b/pre-commit.Dockerfile @@ -0,0 +1,2 @@ +FROM python:3.8.6-buster +RUN python3 -m pip install pre-commit==2.9.3