diff --git a/.github/release-drafter-config.yml b/.github/release-drafter-config.yml index 8bfd8f3..1687859 100644 --- a/.github/release-drafter-config.yml +++ b/.github/release-drafter-config.yml @@ -22,8 +22,7 @@ categories: labels: - documentation -change-template: | - - (#$NUMBER) $TITLE by @$AUTHOR +change-template: "- (#$NUMBER) $TITLE by @$AUTHOR" no-changes-template: 'No significant changes' diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml index 9655936..5d6afe6 100644 --- a/.github/workflows/cla.yaml +++ b/.github/workflows/cla.yaml @@ -4,7 +4,7 @@ on: issue_comment: types: [created] pull_request_target: - types: [opened, closed, synchronize] + types: [opened] permissions: contents: read @@ -21,7 +21,7 @@ jobs: steps: - name: "CLA Assistant" if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' - uses: contributor-assistant/github-action@v2.6.1 + uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 #v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_ACCESS_TOKEN }} diff --git a/.github/workflows/link-checker.yaml b/.github/workflows/link-checker.yaml index 4656d06..3334642 100644 --- a/.github/workflows/link-checker.yaml +++ b/.github/workflows/link-checker.yaml @@ -13,10 +13,31 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Restore lychee cache + uses: actions/cache@v4 + id: restore-cache + with: + path: .lycheecache + key: cache-lychee-${{ github.sha }} + restore-keys: cache-lychee- + - name: Link Checker id: lychee uses: lycheeverse/lychee-action@v2 with: - args: --base . --verbose --no-progress './**/*.md' --accept 100..=103,200..=299,429 + args: >- + './**/*.md' + --verbose + --no-progress + --user-agent 'Mozilla/5.0 (X11; Linux x86_64) Chrome/134.0.0.0' + --retry-wait-time 60 + --max-retries 8 + --accept 100..=103,200..=299,429 + --cookie-jar cookies.json + --exclude-all-private + --max-concurrency 4 + --cache + --cache-exclude-status '429, 500..502' + --max-cache-age 1d format: markdown fail: true diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml new file mode 100644 index 0000000..fc1e926 --- /dev/null +++ b/.github/workflows/security-scan.yml @@ -0,0 +1,59 @@ +name: Security Scan +on: + workflow_dispatch: + inputs: + target: + description: "Scan part" + required: true + default: "docker" + type: choice + options: + - docker + - source + image: + description: "Docker image (for 'docker' target). By default ghcr.io//:latest" + required: false + default: "" + only-high-critical: + description: "Scan only HIGH + CRITICAL" + required: false + default: true + type: boolean + trivy-scan: + description: "Run Trivy scan" + required: false + default: true + type: boolean + grype-scan: + description: "Run Grype scan" + required: false + default: true + type: boolean + continue-on-error: + description: "Continue on error" + required: false + default: true + type: boolean + only-fixed: + description: "Show only fixable vulnerabilities" + required: false + default: true + type: boolean + +permissions: + contents: read + security-events: write + actions: read + packages: read + +jobs: + security-scan: + uses: netcracker/qubership-workflow-hub/.github/workflows/re-security-scan.yml@main + with: + target: ${{ github.event.inputs.target || 'source' }} + image: ${{ github.event.inputs.image || '' }} + only-high-critical: ${{ inputs.only-high-critical}} + trivy-scan: ${{ inputs.trivy-scan }} + grype-scan: ${{ inputs.grype-scan }} + only-fixed: ${{ inputs.only-fixed }} + continue-on-error: ${{ inputs.continue-on-error }} \ No newline at end of file diff --git a/alpine/Dockerfile b/alpine/Dockerfile index eb5d198..b36882e 100644 --- a/alpine/Dockerfile +++ b/alpine/Dockerfile @@ -5,7 +5,7 @@ ENV S3_CERT_PATH_INTERNAL=/s3CertInternal ARG PY_APSW_VER="3.40.1.0" ARG PIP="25.3" -ARG SETUPTOOLS="78.1.1" +ARG SETUPTOOLS="80.9.0" ARG TMP_DIR="/tmp" COPY requirements.txt ${BACKUP_DAEMON_HOME}/ @@ -37,4 +37,4 @@ RUN mkdir -p ${S3_CERT_PATH_INTERNAL} \ VOLUME /backup-storage -CMD ["python3", "/opt/backup/backup-daemon.py"] +CMD ["python3", "/opt/backup/backup-daemon.py"] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index b7bf3d3..5069539 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,8 @@ aniso8601==9.0.1 appdirs==1.4.4 apsw==3.40.1.0 attrs==21.4.0 -boto3==1.28.62 -botocore==1.31.62 +boto3==1.34.63 +botocore==1.34.63 CacheControl==0.12.10 certifi==2024.7.4 charset-normalizer==2.0.7 @@ -37,12 +37,12 @@ pyrsistent==0.18.1 python-dateutil==2.8.2 pytz==2021.3 PyYAML==6.0.1 -requests==2.31.0 +requests==2.32.4 retrying==1.3.3 -s3transfer==0.7.0 +s3transfer==0.10.0 six==1.16.0 toml==0.10.2 tomli==1.2.2 -urllib3==2.0.6 +urllib3==2.6.3 webencodings==0.5.1 -Werkzeug==3.0.6 +Werkzeug==3.1.5 diff --git a/src/db.py b/src/db.py index 6a44e21..175f546 100644 --- a/src/db.py +++ b/src/db.py @@ -13,6 +13,7 @@ # limitations under the License. import logging +import threading import apsw @@ -29,6 +30,8 @@ class DbException(Exception): class DB: + _lock = threading.Lock() + def __init__(self, dbfile): """ Create a connection to sqlite database @@ -41,7 +44,7 @@ def __init__(self, dbfile): self.__dbfile = dbfile try: log.debug("Database file: %s" % self.__dbfile) - self.__cursor = DB.__create_connection(dbfile).cursor() + self.__conn = DB.__create_connection(dbfile) except apsw.Error as err: log.exception("Database error during init: %s" % err) raise DbException("Database error during init") @@ -67,24 +70,27 @@ def __create_connection(db_file): def __create_table(self, query): try: - self.__cursor.execute(query) + cursor = self.__conn.cursor() + with cursor: + cursor.execute(query) except apsw.Error as err: log.exception("Database Error: %s" % err) return 0 @staticmethod def __log_and_execute(cursor, sql, args): - log.debug("SQL command: " + sql.replace('?', '%s') % args) - cursor.execute(sql, args) + with DB._lock: + log.debug("SQL command: " + sql.replace('?', '%s') % args) + cursor.execute(sql, args) def __insert_or_delete(self, query, params, login=False): try: if login: cursor = DB.__create_connection(self.__dbfile).cursor() else: - cursor = self.__cursor - - DB.__log_and_execute(cursor, query, params) + cursor = self.__conn.cursor() + with cursor: + DB.__log_and_execute(cursor, query, params) return 1 except apsw.Error as err: log.exception("Database Error: %s" % err) @@ -95,10 +101,10 @@ def __select(self, query, params, login=False): if login: cursor = DB.__create_connection(self.__dbfile).cursor() else: - cursor = self.__cursor - - DB.__log_and_execute(cursor, query, params) - return cursor.fetchall() + cursor = self.__conn.cursor() + with cursor: + DB.__log_and_execute(cursor, query, params) + return cursor.fetchall() except apsw.Error as err: log.exception("Database Error: %s" % err) return None