diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8f61092..84e1d23 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,10 +1,132 @@ -# Jobs to build debian packages +# Jobs to build and publish deb, rpm and arch based packages include: - - project: 'ProtonVPN/Linux/_gitlab-ci' - ref: public-protonvpn-repo - file: 'gitlab-ci-build-publish-debian.yml' - + - project: 'ProtonVPN/Linux/_gitlab-ci' + ref: public-protonvpn-repo + file: 'gitlab-ci-build-publish-debian.yml' + - project: 'ProtonVPN/Linux/_gitlab-ci' + ref: public-protonvpn-repo + file: 'gitlab-ci-build-publish-rpm.yml' + - project: 'ProtonVPN/Linux/_gitlab-ci' + ref: public-protonvpn-repo + file: 'gitlab-ci-build-publish-arch.yml' + - project: 'agarroux/publish-github' + ref: master + file: '/jobs/release.gitlab-ci.yml' + +default: + image: $CI_REGISTRY_IMAGE:branch-$CI_COMMIT_REF_SLUG + stages: - - build - - publish - - message + - image + - test + - build + - publish + - message + - image-latest + - release + +variables: + CI_REGISTRY_IMAGE_PROTON: "$CI_REGISTRY/infra/kubernetes/images" + PKGNAME_ARCH: "protonvpn-cli" + PKGNAME_RPM: "protonvpn-cli" + ORIGINAL_PKGNAME: "protonvpn-cli" + + +######## Manage the Image ########## +.common-image: + image: $CI_REGISTRY/infra/kubernetes/images/docker:stable + interruptible: true + variables: + DOCKER_HOST: tcp://docker:2375 + services: + - name: $CI_REGISTRY/infra/kubernetes/images/docker:dind + alias: docker + before_script: + - apk update + - apk add make bash git gawk rsync + +## Make image when we push to a branch -> run tests on top of this one +make-image-deb: + stage: image + extends: .common-image + except: + - schedules + - triggers + script: + - make image-deb branch=$CI_COMMIT_REF_SLUG src=ubuntu + +make-image-rpm: + stage: image + extends: make-image-deb + script: + - make image-rpm branch=$CI_COMMIT_REF_SLUG src=fedora + +make-image-arch: + stage: image + extends: make-image-deb + script: + - make image-arch branch=$CI_COMMIT_REF_SLUG src=archlinux + +## Once the CI is green, we retag the current branch-master to latest +publish-latest-deb: + stage: image-latest + extends: .common-image + dependencies: [] # Prevent download + extract artifacts + only: + - master + except: + - schedules + - triggers + script: + - make latest src=ubuntu + +publish-latest-rpm: + extends: publish-latest-deb + script: + - make latest src=fedora + +publish-latest-arch: + extends: publish-latest-deb + script: + - make latest src=archlinux + + +######## CI Jobs ########## +test-deb: + stage: test + image: $CI_REGISTRY_IMAGE:branch-$CI_COMMIT_REF_SLUG-ubuntu + interruptible: true + needs: + - job: make-image-deb + script: + - python3 -m pytest + +test-rpm: + extends: test-deb + needs: + - job: make-image-rpm + image: $CI_REGISTRY_IMAGE:branch-$CI_COMMIT_REF_SLUG-fedora + +test-arch: + extends: test-deb + needs: + - job: make-image-arch + image: $CI_REGISTRY_IMAGE:branch-$CI_COMMIT_REF_SLUG-archlinux + + +## Jobs to publish commits + tags from master to github +# release-publish-github: +# stage: release +# variables: +# RELEASE_SYNC_PUBLIC_URL: git@github.com:repo-username/repo-name.git +# RELEASE_SYNC_TO_BRANCH: 'master' +# RELEASE_SYNC_FROM_BRANCH: 'master' +# extends: .release-sync-commit-shared + +# release-publish-github-tags: +# stage: release +# variables: +# RELEASE_SYNC_PUBLIC_URL: git@github.com:repo-username/repo-name.git +# RELEASE_SYNC_TO_BRANCH: 'master' +# RELEASE_SYNC_FROM_BRANCH: 'master' +# extends: .release-sync-tags-shared diff --git a/Dockerfile.arch b/Dockerfile.arch new file mode 100644 index 0000000..48f395d --- /dev/null +++ b/Dockerfile.arch @@ -0,0 +1,56 @@ +FROM IMAGE_URL_ARCH +ARG pkgname +ENV pkgname=${pkgname:-protonvpn-cli} +RUN pacman -Syu --noconfirm + +RUN pacman -S --noconfirm \ + gcc \ + sudo \ + pacman-contrib \ + base-devel \ + networkmanager \ + networkmanager-openvpn \ + openvpn \ + make \ + python \ + python-pip \ + bash \ + vim \ + nano \ + namcap \ + dbus \ + libnm \ + gnome-keyring \ + # gobject-introspection \ + # pkgconf \ + libsecret + +RUN pacman -S --noconfirm \ + python-pyxdg \ + python-keyring \ + python-distro \ + python-jinja \ + python-gobject \ + python-pythondialog + +RUN python3 -m pip install proton-client && \ + python3 -m pip install --upgrade sentry-sdk==0.10.2 + +RUN pacman -S --noconfirm \ + python-pytest \ + python-pytest-cov + +RUN useradd -ms /bin/bash user +RUN usermod -a -G wheel user +RUN usermod -a -G network user +RUN echo '%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +COPY docker_entry_arch.sh /usr/local/bin +COPY . /home/user/$pkgname + +RUN chown -R user:user /home/user/ +WORKDIR /home/user/$pkgname + +USER user + +ENTRYPOINT ["/usr/local/bin/docker_entry_arch.sh"] diff --git a/Dockerfile.deb b/Dockerfile.deb new file mode 100644 index 0000000..4c8c5f6 --- /dev/null +++ b/Dockerfile.deb @@ -0,0 +1,54 @@ +FROM IMAGE_URL_DEB +ARG pkgname +ENV pkgname=${pkgname:-protonvpn-cli} +RUN apt-get update +RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata + +# Install a few useful packages + +RUN apt-get install -y net-tools \ + apt-utils \ + iproute2 \ + python3 \ + python3-pip \ + network-manager \ + network-manager-openvpn \ + sudo \ + vim \ + pkg-config \ + iputils-ping \ + openvpn \ + libsecret-tools \ + dbus-x11 \ + gnome-keyring \ + libgirepository1.0-dev \ + gir1.2-nm-1.0 \ + libcairo2-dev + +RUN apt-get install -y \ + python3-xdg \ + python3-keyring \ + python3-distro \ + python3-jinja2 \ + python3-dialog + +RUN apt-get install -y \ + python3-pytest \ + python3-pytest-cov + +RUN python3 -m pip install proton-client && \ + python3 -m pip install --upgrade sentry-sdk==0.10.2 + +RUN useradd -ms /bin/bash user +RUN usermod -a -G sudo user +RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +COPY docker_entry_deb.sh /usr/local/bin +COPY . /home/user/$pkgname + +RUN chown -R user:user /home/user/$pkgname +WORKDIR /home/user/$pkgname + +USER user + +ENTRYPOINT ["/usr/local/bin/docker_entry_deb.sh"] diff --git a/Dockerfile.rpm b/Dockerfile.rpm new file mode 100644 index 0000000..4b041ad --- /dev/null +++ b/Dockerfile.rpm @@ -0,0 +1,61 @@ +FROM IMAGE_URL_RPM +ARG pkgname +ENV pkgname=${pkgname:-protonvpn-cli} +RUN dnf update -y + +# Install a few useful packages + +RUN dnf install -y net-tools \ + gcc \ + sudo \ + rpm-build \ + rpm-devel \ + rpmlint \ + rpmdevtools \ + rpm-sign \ + python3 \ + python3-pip \ + NetworkManager \ + NetworkManager-openvpn \ + sudo \ + vim \ + nano \ + pkg-config \ + openvpn \ + openssl-devel \ + openssl-libs \ + dbus-x11 \ + gnome-keyring \ + libsecret \ + gtk3 \ + polkit + +RUN dnf install -y \ + python3-pyxdg \ + python3-dbus \ + python3-keyring \ + python3-distro \ + python3-gobject \ + python3-jinja2 \ + python3-dialog + +RUN python3 -m pip install proton-client && \ + python3 -m pip install --upgrade sentry-sdk==0.10.2 + +RUN dnf install -y \ + python3-pytest \ + python3-pytest-cov + +RUN useradd -ms /bin/bash user +RUN usermod -a -G wheel user +RUN echo '%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +COPY docker_entry_rpm.sh /usr/local/bin +COPY . /home/user/$pkgname + +RUN chown -R user:user /home/user/$pkgname +WORKDIR /home/user/$pkgname + +USER user + +ENTRYPOINT ["/usr/local/bin/docker_entry_rpm.sh"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..afc23e7 --- /dev/null +++ b/Makefile @@ -0,0 +1,120 @@ +.PHONY: image latest latest-tag test deploy-local local login-deploy + +-include .env + +branch ?= master +DOCKERFILE_BUILD=/tmp/Dockerfile.image +NAME_IMAGE ?= "$(CI_REGISTRY_IMAGE)" +TAG_IMAGE := branch-$(subst /,-,$(branch))-$(src) + +# We use :latest so we can use somewhere else, but it's the same as branch-master the other one is for CI +ifeq ($(branch), latest) + TAG_IMAGE=latest +endif + + +IMAGE_URL_DEB ?= $(CI_REGISTRY_IMAGE_PROTON)/ubuntu:latest +IMAGE_URL_RPM ?= $(CI_REGISTRY_IMAGE_PROTON)/fedora:latest +IMAGE_URL_ARCH ?= $(CI_REGISTRY_IMAGE_PROTON)/archlinux:latest +ifndef CI_REGISTRY_IMAGE_PROTON + IMAGE_URL_DEB = ubuntu:latest + IMAGE_URL_RPM = fedora:latest + IMAGE_URL_ARCH = archlinux:latest +endif + +# Run make base to build both images based on ubuntu and fedora +base: image-deb image-rpm image-arch + +# Create the image based on ubuntu +image-deb: image +image-deb: DOCKER_FILE_SOURCE = Dockerfile.deb +image-deb: src = ubuntu + +# Create the image based on fedora +image-rpm: image +image-rpm: DOCKER_FILE_SOURCE = Dockerfile.rpm +image-rpm: src = fedora + +# Create the image based on archlinux +image-arch: image +image-arch: DOCKER_FILE_SOURCE = Dockerfile.arch +image-arch: src = archlinux + +## Make remote image form a branch make image branch= (master default) +image: requirements.txt docker-source + docker build -t $(NAME_IMAGE):$(TAG_IMAGE) -f "$(DOCKERFILE_BUILD)" . + docker push $(NAME_IMAGE):$(TAG_IMAGE) + docker tag $(NAME_IMAGE):$(TAG_IMAGE) $(NAME_IMAGE):$(TAG_IMAGE) + +## We host our own copy of the image ubuntu:latest +docker-source: + sed "s|IMAGE_URL_RPM|$(IMAGE_URL_RPM)|; s|IMAGE_URL_DEB|$(IMAGE_URL_DEB)|; s|IMAGE_URL_ARCH|$(IMAGE_URL_ARCH)|" $(DOCKER_FILE_SOURCE) > /tmp/Dockerfile.image + +requirements.txt: + @ touch requirements.txt + +# Tag the image branch-master as latest +latest: + docker pull $(NAME_IMAGE):branch-master-$(src) + docker tag $(NAME_IMAGE):branch-master-$(src) $(NAME_IMAGE):latest-$(src) + docker push $(NAME_IMAGE):latest-$(src) + +## Build image on local -> name nm-core:latest +local: docker-source + # docker build -t "$(NAME_IMAGE)" -f "$(DOCKERFILE_BUILD)" . + docker build -t $(NAME_IMAGE) -f "$(DOCKERFILE_BUILD)" . + @ rm -rf __SOURCE_APP || true +local: NAME_IMAGE = protonvpn-cli:latest + +local-base: local-deb local-rpm local-arch + +local-deb: local +local-deb: DOCKER_FILE_SOURCE = Dockerfile.deb + +local-rpm: local +local-rpm: DOCKER_FILE_SOURCE = Dockerfile.rpm + +local-arch: local +local-arch: DOCKER_FILE_SOURCE = Dockerfile.arch + +# Build an image from your computer and push it to our repository +deploy-local: login-deploy build tag push + +# If you want to deploy an image to our registry you will need to set these variables inside .env +login-deploy: + docker login -u "$(CI_DEPLOY_USER)" -p "$(CI_JOB_TOKEN)" "$(CI_REGISTRY)" + +######### Not linked to the image ############### + +## Run tests against the latest version of the deb from your code +test-deb: local-deb + # Keep -it because with colors it's better + @ docker run \ + --rm \ + -it \ + --privileged \ + --volume $(PWD)/home/user/protonvpn-cli/ \ + protonvpn-cli:latest \ + python3 -m pytest + +## Run tests against the latest version of the rpm from your code +test-rpm: local-rpm + # Keep -it because with colors it's better + @ docker run \ + --rm \ + -it \ + --privileged \ + --volume $(PWD)/home/user/protonvpn-cli/ \ + protonvpn-cli:latest \ + python3 -m pytest + +## Run tests against the latest version of the arch from your code +test-arch: local-arch + # Keep -it because with colors it's better + @ docker run \ + --rm \ + -it \ + --privileged \ + --volume $(PWD)/home/user/protonvpn-cli/ \ + protonvpn-cli:latest \ + python3 -m pytest diff --git a/arch/PKGBUILD b/arch/PKGBUILD new file mode 100644 index 0000000..b88a5dc --- /dev/null +++ b/arch/PKGBUILD @@ -0,0 +1,23 @@ +# Maintainer: Proton Technologies AG +pkgname=protonvpn-cli +pkgver=3.2.0 +pkgrel=1 +pkgdesc="Official Linux CLI client" +arch=("any") +url="https://github.com/ProtonVPN/" +license=("GPL3") +depends=("python-protonvpn-nm-lib" "python-pythondialog") +makedepends=("python-setuptools") +source=("$pkgname.tar.gz") +sha256sums=(.) +validpgpkeys=("A884 41BD 4864 F95B EE08 E63A 71EB 4740 1994 0E11") + +build() { + cd "$pkgname" + python setup.py build +} + +package() { + cd "$pkgname" + python setup.py install --root="$pkgdir" --optimize=1 +} diff --git a/docker_entry_arch.sh b/docker_entry_arch.sh new file mode 100755 index 0000000..a781ed7 --- /dev/null +++ b/docker_entry_arch.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Start dbus system +sudo mkdir -p /var/run/dbus && \ +sudo dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address + +# Start shell to start keyring +eval "$(dbus-launch --sh-syntax)" + +# Create necessary non-root dirs for keyring +mkdir -p ~/.cache +mkdir -p ~/.local/share/keyrings # where the automatic keyring is created + +# 1. Create the keyring manually with a dummy password in stdin +eval "$(printf '\n' | gnome-keyring-daemon --unlock)" + +# 2. Start the daemon, using the password to unlock the just-created keyring: +eval "$(printf '\n' | /usr/bin/gnome-keyring-daemon --start)" + +# Disable connectivity check +printf "[connectivity]\nuri=http://www.archlinux.org/check_network_status.txt\ninterval=0" | sudo tee /etc/NetworkManager/conf.d/20-connectivity.conf + +# Add polkit rules so that user can make any actions +printf "\npolkit.addRule(function(action, subject) {\n\tif (action.id.indexOf('org.freedesktop.NetworkManager.') == 0 && subject.isInGroup('network')) {\n\t\treturn polkit.Result.YES;\n\t}\n});\n" | sudo tee /etc/polkit-1/rules.d/50-org.freedesktop.NetworkManager.rules + +# Start network manager +sudo /sbin/NetworkManager start + +if [ -f .env ]; then + echo 'find local .env ~ load new env'; + export $(cat .env | xargs); + env; +fi + +exec "$@"; diff --git a/docker_entry_deb.sh b/docker_entry_deb.sh new file mode 100755 index 0000000..df80ad4 --- /dev/null +++ b/docker_entry_deb.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Start network manager and dbus system +sudo /etc/init.d/dbus start && \ +sudo /etc/init.d/network-manager start + +# Start gnome-keyring daemon at bash shell init and launch interactive dbus session +echo 'eval "$(printf '\\n' | gnome-keyring-daemon --unlock)"' >> ~/.bashrc + +export $(dbus-launch) + +## 1. Create the keyring manually with a dummy password in stdin +eval "$(printf '\n' | gnome-keyring-daemon --unlock)" + +if [ -f .env ]; then + echo 'find local .env ~ load new env'; + export $(cat .env | xargs); + env; +fi + +# Add polkit rules so that user can make any actions +sudo bash -c "cat < /etc/polkit-1/localauthority/50-local.d/org.freedesktop.NetworkManager.pkla +[nm-applet] +Identity=unix-user:user +Action=org.freedesktop.NetworkManager.* +ResultAny=yes +ResultInactive=no +ResultActive=yes +EOT" + +exec "$@"; diff --git a/docker_entry_rpm.sh b/docker_entry_rpm.sh new file mode 100755 index 0000000..f3df577 --- /dev/null +++ b/docker_entry_rpm.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Start dbus system +sudo mkdir -p /var/run/dbus && \ +sudo dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address + +# Start shell to start keyring +eval "$(dbus-launch --sh-syntax)" + +# Create necessary non-root dirs for keyring +mkdir -p ~/.cache +mkdir -p ~/.local/share/keyrings # where the automatic keyring is created + +# 1. Create the keyring manually with a dummy password in stdin +eval "$(printf '\n' | gnome-keyring-daemon --unlock)" + +# 2. Start the daemon, using the password to unlock the just-created keyring: +eval "$(printf '\n' | /usr/bin/gnome-keyring-daemon --start)" + +# Start network manager +sudo /sbin/NetworkManager start + +if [ -f .env ]; then + echo 'find local .env ~ load new env'; + export $(cat .env | xargs); + env; +fi + +# Add polkit rules so that user can make any actions +sudo bash -c "cat < /etc/polkit-1/localauthority/50-local.d/org.freedesktop.NetworkManager.pkla +[nm-applet] +Identity=unix-user:user +Action=org.freedesktop.NetworkManager.* +ResultAny=yes +ResultInactive=no +ResultActive=yes +EOT" + +exec "$@"; diff --git a/protonvpn_cli/constants.py b/protonvpn_cli/constants.py index 6586dec..c275872 100644 --- a/protonvpn_cli/constants.py +++ b/protonvpn_cli/constants.py @@ -1,4 +1,4 @@ -APP_VERSION = "3.1.0" +APP_VERSION = "3.2.0" MAIN_CLI_HELP = """ ProtonVPN CLI v{} diff --git a/rpmbuild/BUILD/.gitkeep b/rpmbuild/BUILD/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rpmbuild/BUILDROOT/.gitkeep b/rpmbuild/BUILDROOT/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rpmbuild/RPMS/.gitkeep b/rpmbuild/RPMS/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rpmbuild/SOURCES/.gitkeep b/rpmbuild/SOURCES/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rpmbuild/SPECS/protonvpn-cli.spec b/rpmbuild/SPECS/protonvpn-cli.spec new file mode 100644 index 0000000..a7b630a --- /dev/null +++ b/rpmbuild/SPECS/protonvpn-cli.spec @@ -0,0 +1,40 @@ +%define unmangled_name protonvpn-cli +%define version 3.2.0 +%define release 1 + +Summary: ProtonVPN CLI +Name: protonvpn-cli +Version: %{version} +Release: %{release} +Source0: %{unmangled_name}-%{version}.tar.gz +License: MIT +Group: Development/Libraries +BuildRoot: %{_tmppath}/%{unmangled_name}-%{version}-%{release}-buildroot +Prefix: %{_prefix} +BuildArch: noarch +Vendor: Proton Technologies AG +Url: https://github.com/ProtonVPN +Requires: python3-protonvpn-nm-lib +Requires: python3-dialog + + +%{?python_disable_dependency_generator} + +%description +Official Linux CLI client. + + +%prep +%setup -n %{unmangled_name}-%{version} -n %{unmangled_name}-%{version} + +%build +python3 setup.py build + +%install +python3 setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES + +%clean +rm -rf $RPM_BUILD_ROOT + +%files -f INSTALLED_FILES +%defattr(-,root,root) diff --git a/rpmbuild/SRPMS/.gitkeep b/rpmbuild/SRPMS/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cli_wrapper.py b/tests/test_cli_wrapper.py new file mode 100644 index 0000000..45b2bd0 --- /dev/null +++ b/tests/test_cli_wrapper.py @@ -0,0 +1,2 @@ +def test_placeholder(): + pass \ No newline at end of file