diff --git a/.github/workflows/.github-ci.yaml b/.github/workflows/.github-ci.yaml new file mode 100644 index 0000000..aa7e6d6 --- /dev/null +++ b/.github/workflows/.github-ci.yaml @@ -0,0 +1,94 @@ +name: Build, Test, and Deploy Docker Image + +on: + push: + branches: [eoepca-beta01] + +jobs: + build: + runs-on: ubuntu-latest + steps: + # Step 1: Checkout repository + - uses: actions/checkout@v4 + + # Step 2: Install Trivy + - name: Install Trivy + run: | + sudo apt-get update -y + sudo apt-get install -y wget apt-transport-https gnupg lsb-release + wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - + echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list + sudo apt-get update -y + sudo apt-get install -y trivy + + # Step 3: Build Docker image + - name: Build Docker image + run: | + APP_NAME="application-hub-context" + APP_VERSION="1.6.2" + tag="${APP_NAME}:${APP_VERSION}" + echo "${{ secrets.CR_PASSWORD }}" | docker login -u "${{ secrets.CR_USERNAME }}" --password-stdin "${{ secrets.CR_REGISTRY }}" + docker build -t "${{ secrets.CR_REGISTRY }}/${{ secrets.CR_REPO }}/${tag}" --file Dockerfile . + + + # Step 4: Save Docker image as tar.gz + - name: Save Docker Image as tar.gz + run: | + APP_NAME="application-hub-context" + APP_VERSION="1.6.2" + tag="${APP_NAME}:${APP_VERSION}" + docker save "${{ secrets.CR_REGISTRY }}/${{ secrets.CR_REPO }}/${tag}" -o "${APP_NAME}_${APP_VERSION}.tar" + tar -czf "${APP_NAME}_${APP_VERSION}.tar.gz" "${APP_NAME}_${APP_VERSION}.tar" + + # Step 5: Upload Docker Image tar.gz as an artifact + - name: Upload Docker Image Artifact + uses: actions/upload-artifact@v3 + with: + name: docker-image-tar + path: application-hub-context_1.6.2.tar.gz + + # Step 6: Scan Docker Image with Trivy + - name: Scan Docker Image with Trivy + run: | + APP_NAME="application-hub-context" + APP_VERSION="1.6.2" + tag="${APP_NAME}:${APP_VERSION}" + echo "${{ secrets.CR_PASSWORD }}" | docker login -u "${{ secrets.CR_USERNAME }}" --password-stdin "${{ secrets.CR_REGISTRY }}" + trivy image --no-progress --exit-code 1 --severity HIGH,CRITICAL,UNKNOWN --format table "${{ secrets.CR_REGISTRY }}/${{ secrets.CR_REPO }}/${tag}" + + deploy: + needs: build + runs-on: ubuntu-latest + steps: + # Step 1: Checkout repository + - uses: actions/checkout@v4 + + # Step 2: Download Docker Image tar.gz Artifact + - name: Download Docker Image Artifact + uses: actions/download-artifact@v3 + with: + name: docker-image-tar + + # Step 3: Extract the Docker Image tar.gz + - name: Extract Docker Image tar.gz + run: | + tar -xzf application-hub-context_1.6.2.tar.gz + + # Step 4: Load Docker Image + - name: Load Docker Image + run: | + docker load -i application-hub-context_1.6.2.tar + + # Step 5: Log in to Docker Registry (use GitHub secrets for security) + - name: Login to Docker Registry + run: | + echo "${{ secrets.CR_PASSWORD }}" | docker login -u "${{ secrets.CR_USERNAME }}" --password-stdin "${{ secrets.CR_REGISTRY }}" + + # Step 6: Push Docker Image to Registry + - name: Push Docker Image to Registry + run: | + APP_NAME="application-hub-context" + APP_VERSION="1.6.2" + tag="${APP_NAME}:${APP_VERSION}" + docker push "${{ secrets.CR_REGISTRY }}"/"${{ secrets.CR_REPO }}"/${tag} + diff --git a/Dockerfile b/Dockerfile index 87b350c..d866f6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM jupyterhub/k8s-hub:2.0.0 +FROM ghcr.io/eoepca/container-k8s-hub/container-k8s-hub:2.0.0 ARG NB_USER=johub ARG NB_UID=1001 @@ -6,35 +6,53 @@ ARG HOME=/home/johub USER root -RUN apt update && \ - apt install npm git sudo -y && \ - npm install -g configurable-http-proxy - -RUN adduser --disabled-password \ - --gecos "Default user" \ +# Packages update and dependencies installation +RUN microdnf update -y && \ + microdnf install -y \ + npm \ + git \ + sudo \ + python3-pip \ + python3-devel \ + gcc \ + libcurl-devel \ + openssl-devel \ + && microdnf clean all + +# Installation of configurable-http-proxy via npm +RUN npm install -g configurable-http-proxy + +# User creation +RUN adduser \ --uid ${NB_UID} \ --home ${HOME} \ - --force-badname \ - ${NB_USER} + ${NB_USER} \ + --comment "Default user" \ + --shell /bin/bash -RUN adduser jovyan sudo && \ - echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers +# Add jovyan to the sudoers group +RUN usermod -aG wheel jovyan && \ + echo '%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers +# Python packages installation from requirements.txt COPY requirements.txt /tmp/requirements.txt -RUN pip3 install --upgrade --no-cache-dir \ - setuptools \ - pip +RUN pip3 install --upgrade --no-cache-dir setuptools pip +# Specific Python dependencies installation RUN PYCURL_SSL_LIBRARY=openssl \ - pip install --no-cache-dir \ - -r /tmp/requirements.txt + pip install --no-cache-dir -r /tmp/requirements.txt + +# Check and correct requirejs version +RUN sed -i 's/"version": "[^"]*"/"version": "2.3.7"/' /usr/local/share/jupyterhub/static/components/requirejs/package.json -# So we can actually write a db file here +# Set permission on the directory /srv/jupyterhub RUN chown ${NB_USER}:${NB_USER} /srv/jupyterhub COPY . /tmp -RUN cd /tmp && python setup.py install +RUN cd /tmp && python3 setup.py install +# Set not root user USER ${NB_USER} +# Command to start jupyterhub CMD ["jupyterhub", "--config", "/etc/jupyterhub/jupyterhub_config.py"] diff --git a/requirements.in b/requirements.in index 1e7680c..cfea6af 100644 --- a/requirements.in +++ b/requirements.in @@ -8,17 +8,17 @@ # https://github.com/jazzband/pip-tools -pyjwt -jupyterhub -pytest -pytest-asyncio -pytest-cov -requests-mock -jupyterhub-kubespawner -httplib2 -oauthenticator -jupyterhub-idle-culler -kubernetes -loguru -addict -pydantic>=2 +pyjwt==2.9.0 +jupyterhub==5.1.0 +pytest==8.3.3 +pytest-asyncio==0.24.0 +pytest-cov==5.0.0 +requests-mock==1.12.1 +jupyterhub-kubespawner==6.2.0 +httplib2==0.22.0 +oauthenticator==17.0.0 +jupyterhub-idle-culler==1.4.0 +kubernetes==31.0.0 +loguru==0.7.2 +addict==2.4.0 +pydantic==2.9.2 diff --git a/requirements.txt b/requirements.txt index 8c2f081..157fe5e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,238 +1,109 @@ -# -# This file is autogenerated by pip-compile with python 3.8 -# To update, run: -# -# pip-compile requirements.in -# addict==2.4.0 - # via -r requirements.in -aiohttp==3.8.4 - # via kubernetes-asyncio +aiohappyeyeballs==2.4.0 +aiohttp==3.10.6 aiosignal==1.3.1 - # via aiohttp -alembic==1.11.1 - # via jupyterhub -annotated-types==0.6.0 - # via pydantic +alembic==1.13.3 +annotated-types==0.7.0 +arrow==1.3.0 async-generator==1.10 - # via jupyterhub -async-timeout==4.0.2 - # via aiohttp -attrs==23.1.0 - # via - # aiohttp - # jsonschema -cachetools==5.3.1 - # via google-auth -certifi==2023.5.7 - # via - # kubernetes - # kubernetes-asyncio - # requests -certipy==0.1.3 - # via jupyterhub -cffi==1.15.1 - # via cryptography -charset-normalizer==3.1.0 - # via - # aiohttp - # requests -coverage[toml]==7.2.7 - # via pytest-cov -cryptography==41.0.1 - # via pyopenssl +async-timeout==4.0.3 +attrs==24.2.0 +bcrypt==4.2.0 +cachetools==5.5.0 +certifi==2024.8.30 +certipy==0.2.1 +cffi==1.17.1 +charset-normalizer==3.3.2 +coverage==7.6.1 +cryptography==43.0.1 +durationpy==0.7 escapism==1.0.1 - # via jupyterhub-kubespawner -exceptiongroup==1.1.1 - # via pytest -frozenlist==1.3.3 - # via - # aiohttp - # aiosignal -google-auth==2.19.1 - # via kubernetes -greenlet==2.0.2 - # via sqlalchemy +exceptiongroup==1.2.2 +fqdn==1.5.1 +frozenlist==1.4.1 +google-auth==2.35.0 +greenlet==3.1.1 httplib2==0.22.0 - # via -r requirements.in -idna==3.4 - # via - # requests - # yarl -importlib-metadata==6.8.0 - # via - # alembic - # jupyterhub -importlib-resources==6.1.1 - # via - # alembic - # jsonschema +idna==3.10 +importlib_metadata==8.5.0 +importlib_resources==6.4.5 iniconfig==2.0.0 - # via pytest -jinja2==3.1.2 - # via - # jupyterhub - # jupyterhub-kubespawner -jsonschema==4.17.3 - # via - # jupyter-telemetry - # oauthenticator +isoduration==20.11.0 +Jinja2==3.1.4 +jsonpointer==3.0.0 +jsonschema==4.23.0 +jsonschema-specifications==2023.12.1 +jupyter-events==0.10.0 jupyter-telemetry==0.1.0 - # via jupyterhub -jupyterhub==4.0.0 - # via - # -r requirements.in - # jupyterhub-kubespawner - # oauthenticator -jupyterhub-idle-culler==1.2.1 - # via -r requirements.in -jupyterhub-kubespawner==6.0.0 - # via -r requirements.in -kubernetes==26.1.0 - # via -r requirements.in -kubernetes-asyncio==24.2.3 - # via jupyterhub-kubespawner -loguru==0.7.0 - # via -r requirements.in -mako==1.2.4 - # via alembic -markupsafe==2.1.3 - # via - # jinja2 - # mako -multidict==6.0.4 - # via - # aiohttp - # yarl -oauthenticator==15.1.0 - # via -r requirements.in +jupyterhub==5.1.0 +jupyterhub-firstuseauthenticator==1.1.0 +jupyterhub-hmacauthenticator==1.0 +jupyterhub-idle-culler==1.4.0 +jupyterhub-kubespawner==6.2.0 +jupyterhub-ldapauthenticator==1.3.2 +jupyterhub-ltiauthenticator==1.6.2 +jupyterhub-nativeauthenticator==1.3.0 +jupyterhub-tmpauthenticator==1.0.0 +kubernetes==31.0.0 +kubernetes_asyncio==31.1.0 +ldap3==2.9.1 +loguru==0.7.2 +Mako==1.3.5 +MarkupSafe==2.1.5 +multidict==6.1.0 +mwoauth==0.4.0 +nullauthenticator==1.0.0 +oauthenticator==17.0.0 oauthlib==3.2.2 - # via - # jupyterhub - # requests-oauthlib -packaging==23.1 - # via - # jupyterhub - # pytest -pamela==1.1.0 - # via jupyterhub -pkgutil-resolve-name==1.3.10 - # via jsonschema -pluggy==1.0.0 - # via pytest -prometheus-client==0.17.0 - # via jupyterhub -pyasn1==0.5.0 - # via - # pyasn1-modules - # rsa -pyasn1-modules==0.3.0 - # via google-auth -pycparser==2.21 - # via cffi -pydantic==2.4.2 - # via -r requirements.in -pydantic-core==2.10.1 - # via pydantic -pyjwt==2.7.0 - # via -r requirements.in -pyopenssl==23.2.0 - # via certipy -pyparsing==3.0.9 - # via httplib2 -pyrsistent==0.19.3 - # via jsonschema -pytest==7.3.1 - # via - # -r requirements.in - # pytest-asyncio - # pytest-cov -pytest-asyncio==0.21.0 - # via -r requirements.in -pytest-cov==4.1.0 - # via -r requirements.in -python-dateutil==2.8.2 - # via - # jupyterhub - # jupyterhub-idle-culler - # kubernetes - # kubernetes-asyncio +onetimepass==1.0.1 +packaging==24.1 +pamela==1.2.0 +pkgutil_resolve_name==1.3.10 +pluggy==1.5.0 +prometheus_client==0.21.0 +psycopg2-binary==2.9.9 +py-spy==0.3.14 +pyasn1==0.6.1 +pyasn1_modules==0.4.1 +pycparser==2.22 +pycurl==7.45.3 +pydantic==2.9.2 +pydantic_core==2.23.4 +PyJWT==2.9.0 +PyMySQL==1.1.1 +pyOpenSSL==24.2.1 +pyparsing==3.1.4 +pyrsistent==0.20.0 +pytest==8.3.3 +pytest-asyncio==0.24.0 +pytest-cov==5.0.0 +python-dateutil==2.9.0.post0 python-json-logger==2.0.7 - # via jupyter-telemetry -python-slugify==8.0.1 - # via jupyterhub-kubespawner -pyyaml==6.0 - # via - # jupyterhub-kubespawner - # kubernetes - # kubernetes-asyncio -requests==2.31.0 - # via - # jupyterhub - # kubernetes - # oauthenticator - # requests-mock - # requests-oauthlib -requests-mock==1.10.0 - # via -r requirements.in -requests-oauthlib==1.3.1 - # via kubernetes +python-slugify==8.0.4 +PyYAML==6.0.2 +referencing==0.35.1 +requests==2.32.3 +requests-mock==1.12.1 +requests-oauthlib==2.0.0 +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +rpds-py==0.20.0 rsa==4.9 - # via google-auth -ruamel-yaml==0.17.31 - # via - # jupyter-telemetry - # oauthenticator -ruamel-yaml-clib==0.2.7 - # via ruamel-yaml +ruamel.yaml==0.18.6 +ruamel.yaml.clib==0.2.8 six==1.16.0 - # via - # google-auth - # kubernetes - # kubernetes-asyncio - # python-dateutil - # requests-mock -sqlalchemy==2.0.15 - # via - # alembic - # jupyterhub +SQLAlchemy==2.0.35 +sqlalchemy-cockroachdb==2.0.2 +statsd==4.0.1 text-unidecode==1.3 - # via python-slugify tomli==2.0.1 - # via - # coverage - # pytest -tornado==6.3.2 - # via - # jupyterhub - # jupyterhub-idle-culler -traitlets==5.9.0 - # via - # jupyter-telemetry - # jupyterhub - # jupyterhub-kubespawner -typing-extensions==4.6.3 - # via - # alembic - # annotated-types - # pydantic - # pydantic-core - # sqlalchemy -urllib3==1.26.16 - # via - # google-auth - # jupyterhub-kubespawner - # kubernetes - # kubernetes-asyncio - # requests -websocket-client==1.5.2 - # via kubernetes -yarl==1.9.2 - # via aiohttp -zipp==3.17.0 - # via - # importlib-metadata - # importlib-resources - -# The following packages are considered to be unsafe in a requirements file: -# setuptools +tornado==6.4.1 +traitlets==5.14.3 +types-python-dateutil==2.9.0.20240906 +typing_extensions==4.12.2 +uri-template==1.3.0 +urllib3==2.2.3 +webcolors==24.8.0 +websocket-client==1.8.0 +yarl==1.12.1 +zipp==3.20.2