diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8014dd9..ee5fa3e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -4,13 +4,6 @@ on: pull_request: jobs: - unit-test: - name: Unit tests - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Install tox - run: | - python -m pip install --upgrade pip - pip install tox - - run: tox -e unit + unit-tests: + uses: canonical/operator-workflows/.github/workflows/test.yaml@main + secrets: inherit diff --git a/.licenserc.yaml b/.licenserc.yaml new file mode 100644 index 0000000..925e252 --- /dev/null +++ b/.licenserc.yaml @@ -0,0 +1,37 @@ +header: + license: + spdx-id: Apache-2.0 + copyright-owner: Canonical Ltd. + content: | + Copyright [year] [owner] + See LICENSE file for licensing details. + paths: + - '**' + paths-ignore: + - '.github/**' + - '**/.gitkeep' + - '**/*.cfg' + - '**/*.conf' + - '**/*.j2' + - '**/*.json' + - '**/*.md' + - '**/*.rule' + - '**/*.tmpl' + - '**/*.txt' + - '.codespellignore' + - '.dockerignore' + - '.flake8' + - '.jujuignore' + - '.gitignore' + - '.licenserc.yaml' + - '.trivyignore' + - '.woke.yaml' + - '.woke.yml' + - 'CODEOWNERS' + - 'icon.svg' + - 'LICENSE' + - 'trivy.yaml' + - 'zap_rules.tsv' + - 'lib/**' + - 'files/**' + comment: on-failure diff --git a/.trivyignore b/.trivyignore index a82a579..8d35a8e 100644 --- a/.trivyignore +++ b/.trivyignore @@ -14,3 +14,4 @@ CVE-2022-28948 CVE-2022-3064 CVE-2022-32149 CVE-2022-41723 +CVE-2023-2515 diff --git a/.woke.yml b/.woke.yml new file mode 100644 index 0000000..e91f0f2 --- /dev/null +++ b/.woke.yml @@ -0,0 +1,4 @@ +rules: + # Ignore "whitelist" and "master". + - name: whitelist + - name: master diff --git a/COPYRIGHT b/COPYRIGHT deleted file mode 100644 index 1889423..0000000 --- a/COPYRIGHT +++ /dev/null @@ -1,16 +0,0 @@ -Format: http://dep.debian.net/deps/dep5/ - -Files: * -Copyright: Copyright 2020, Canonical Ltd. -License: GPL-3 - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License version 3, as - published by the Free Software Foundation. - . - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranties of - MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - PURPOSE. See the GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see . diff --git a/actions.yaml b/actions.yaml index d7e3b8e..2ccf890 100644 --- a/actions.yaml +++ b/actions.yaml @@ -1,3 +1,5 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. grant-admin-role: description: > Grant the "system_admin" role to a user. The user will need to log out and diff --git a/charmcraft.yaml b/charmcraft.yaml index 07b8d79..8c56ce9 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -1,3 +1,5 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. type: "charm" bases: - build-on: diff --git a/config.yaml b/config.yaml index c9a6b15..26ecf69 100644 --- a/config.yaml +++ b/config.yaml @@ -1,3 +1,5 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. options: clustering: type: boolean diff --git a/mattermost.Dockerfile b/mattermost.Dockerfile index d7bdf8b..84907c7 100644 --- a/mattermost.Dockerfile +++ b/mattermost.Dockerfile @@ -1,3 +1,5 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. FROM ubuntu:focal AS canonical_flavour_builder # Avoid needing any input from package installs. @@ -15,11 +17,11 @@ RUN apt-get -y update && \ apt-get -y --no-install-recommends install \ git \ curl \ - make \ - && \ - curl -s https://deb.nodesource.com/setup_16.x | bash && \ - apt-get -y update && \ - apt-get -y --no-install-recommends install nodejs + make && \ + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash && \ + bash -c "source /root/.nvm/nvm.sh && nvm install v16.14.0" + +ENV PATH="$PATH:/root/.nvm/versions/node/v16.14.0/bin" # Patch the https-proxy-agent library used by npm to limit the open socket # number connected to proxy server. @@ -31,16 +33,19 @@ RUN apt-get -y update && \ COPY files/canonical_flavour/https-proxy-agent.patch patch/https-proxy-agent.patch RUN curl -sSL https://github.com/TooTallNate/node-https-proxy-agent/archive/refs/tags/5.0.1.tar.gz -o node-https-proxy-agent.tar.gz && \ - echo "1afed785d8d9deadac371824d6622aeabc7919ed6db3b3a6ad0033bd1105d2f4 node-https-proxy-agent.tar.gz" | shasum -c && \ - tar -xf node-https-proxy-agent.tar.gz && \ - cd node-https-proxy-agent-5.0.1 && \ - git apply /patch/https-proxy-agent.patch && \ - npm config set progress=false loglevel=info && \ - npm install && \ + echo "36ee41503f9245b2b8ce3e4725ac966cf9a391f4 node-https-proxy-agent.tar.gz" | shasum -c && \ + tar -xf node-https-proxy-agent.tar.gz + +WORKDIR /proxy-agents-5.0.1 +RUN git apply /patch/https-proxy-agent.patch && \ + npm config set progress=false loglevel=info + +RUN npm install && \ npm run build && \ rm -rf /usr/lib/node_modules/npm/node_modules/https-proxy-agent/ && \ - mv ./dist /usr/lib/node_modules/npm/node_modules/https-proxy-agent && \ - cd .. + mv ./dist /root/.nvm/versions/node/v16.14.0/lib/node_modules/https-proxy-agent + +WORKDIR / COPY files/canonical_flavour/themes.patch patch/themes.patch @@ -66,10 +71,10 @@ LABEL com.canonical.mattermost-edition=${edition} # We use "set -o pipefail" SHELL ["/bin/bash", "-c"] -# python3-yaml needed to run juju actions, xmlsec1 needed if UseNewSAMLLibrary is set to false (the default) +# xmlsec1 needed if UseNewSAMLLibrary is set to false (the default) RUN apt-get -qy update && \ apt-get -qy upgrade && \ - apt-get -qy install curl python3-yaml xmlsec1 && \ + apt-get -qy install curl xmlsec1 && \ rm -f /var/lib/apt/lists/*_* RUN mkdir -p /mattermost/data /mattermost/plugins /mattermost/client/plugins && \ diff --git a/metadata.yaml b/metadata.yaml index d2ffc5b..57cdafa 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -1,3 +1,5 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. name: mattermost-k8s display-name: Mattermost summary: Messaging platform for team collaboration. diff --git a/src/charm.py b/src/charm.py index 76cf8e8..50139ce 100755 --- a/src/charm.py +++ b/src/charm.py @@ -3,7 +3,7 @@ # See LICENSE file for licensing details. import logging -import subprocess +import subprocess # nosec from ipaddress import ip_network from urllib.parse import urlparse from zlib import crc32 @@ -27,7 +27,7 @@ # Default port, enforced via envConfig to prevent operator error METRICS_PORT = 8067 DATABASE_NAME = "mattermost" -LICENSE_SECRET_KEY_NAME = "licence" +LICENSE_SECRET_KEY_NAME = "licence" # nosec REQUIRED_S3_SETTINGS = ["s3_bucket", "s3_region", "s3_access_key_id", "s3_secret_access_key"] REQUIRED_SETTINGS = ["mattermost_image_path"] REQUIRED_SSO_SETTINGS = ["licence", "site_url"] @@ -111,7 +111,7 @@ def _on_grant_admin_role_action(self, event): """Handle the grant-admin-role action.""" user = event.params["user"] cmd = ["/mattermost/bin/mattermost", "roles", "system_admin", user] - granted = subprocess.run(cmd, capture_output=True) + granted = subprocess.run(cmd, capture_output=True) # nosec if granted.returncode != 0: event.fail( "Failed to run '{}'. Output was:\n{}".format( diff --git a/tests/conftest.py b/tests/conftest.py index 7ea5bba..225d580 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ # Copyright 2023 Canonical Ltd. -# see LICENCE file for details. +# See LICENSE file for licensing details. """General configuration module for tests.""" import pytest @@ -11,6 +11,7 @@ def pytest_addoption(parser: pytest.Parser): Args: parser: Pytest parser used to add arguments to console commands """ + parser.addoption("--charm-file", action="store") # Localstack instance URL parser.addoption("--localstack-url", action="store", default="") # OCI image of mattermost diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 994f492..6241d7f 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -48,6 +48,15 @@ def mattermost_image(request): return request.config.getoption("--mattermost-image") +@fixture(scope="module") +def charm_file(request): + """Get the charm file from the --charm-file argument. + + Return a the mattermost image name + """ + return request.config.getoption("--charm-file") + + @pytest_asyncio.fixture(scope="module", name="model") async def model_fixture(ops_test: OpsTest) -> ops.model.Model: """Provide current test model.""" @@ -63,15 +72,14 @@ async def app( model: ops.model.Model, app_name: str, mattermost_image: str, + charm_file: str, ): """Mattermost charm used for integration testing. Builds the charm and deploys it and the relations it depends on. """ await model.deploy("postgresql-k8s"), - - charm = await ops_test.build_charm(".") - application = await model.deploy(charm, application_name=app_name, series="focal") + application = await model.deploy(f"./{charm_file}", application_name=app_name, series="focal") await model.wait_for_idle() # Change the image that will be used for the mattermost container @@ -83,7 +91,7 @@ async def app( { "MM_FILESETTINGS_AMAZONS3SSL": "false", "MM_SERVICESETTINGS_ENABLELOCALMODE": "true", - "MM_SERVICESETTINGS_LOCALMODESOCKETLOCATION": "/tmp/mattermost.socket", + "MM_SERVICESETTINGS_LOCALMODESOCKETLOCATION": "/tmp/mattermost.socket", # nosec } ), } diff --git a/tests/integration/localstack-installation.sh b/tests/integration/localstack-installation.sh index 97a9e07..e43e73e 100644 --- a/tests/integration/localstack-installation.sh +++ b/tests/integration/localstack-installation.sh @@ -1,4 +1,6 @@ #!/bin/bash +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. pip install pip --upgrade pip install pyopenssl --upgrade diff --git a/tox.ini b/tox.ini index 9247d36..63edd7a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,10 @@ -# Copyright 2022 Canonical Ltd. +# Copyright 2023 Canonical Ltd. # See LICENSE file for licensing details. [tox] skipsdist=True skip_missing_interpreters = True -envlist = unit, integration +envlist = lint, unit, static, coverage-report [vars] src_path = {toxinidir}/src/ @@ -57,18 +57,18 @@ deps = types-requests -r{toxinidir}/requirements.txt commands = - pydocstyle {[vars]src_path} + pydocstyle {[vars]src_path} --ignore=D100,D101,D107,D203,D205,D213,D209,D400,D406,D407,D413,D415 # uncomment the following line if this charm owns a lib # codespell {[vars]lib_path} codespell {toxinidir} --skip {toxinidir}/.git --skip {toxinidir}/.tox \ --skip {toxinidir}/build --skip {toxinidir}/lib --skip {toxinidir}/venv \ --skip {toxinidir}/.mypy_cache --skip {toxinidir}/icon.svg # pflake8 wrapper supports config from pyproject.toml - pflake8 {[vars]all_path} --ignore=W503 + pflake8 {[vars]all_path} --ignore=D100,D101,D107,D202,D205,D209,D212,D403,D415,DCO010,DCO020,DCO030,DCO031,DCO040,DCO050,DCO060,E501,N806,W503,W505 isort --check-only --diff {[vars]all_path} black --check --diff {[vars]all_path} - mypy {[vars]all_path} - pylint {[vars]all_path} + mypy {[vars]all_path} --disable-error-code attr-defined --disable-error-code name-defined --disable-error-code index --disable-error-code misc --disable-error-code union-attr + pylint {[vars]all_path} --disable=C0103,C0114,C0209,C0115,C0116,C0301,E0401,E1101,R0205,R0913,R0914,R1705,R1710,W0106,W0212,W0621,W1510 [testenv:unit] commands = @@ -81,6 +81,23 @@ setenv = PYTHONPATH={toxinidir}/src:{toxinidir}/build/lib:{toxinidir}/build/venv TZ=UTC +[testenv:coverage-report] +description = Create test coverage report +deps = + coverage[toml] + pytest + -r{toxinidir}/requirements.txt +commands = + coverage report + +[testenv:static] +description = Run static analysis tests +deps = + bandit[toml] + -r{toxinidir}/requirements.txt +commands = + bandit -c {toxinidir}/pyproject.toml -r {[vars]src_path} {[vars]tst_path} + [testenv:integration] passenv = HOME