Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PPR API update to poetry; GCP CI, CD set up #2072

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions mhr-api/src/mhr_api/resources/v1/admin_registrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from mhr_api.reports.v2.report_utils import ReportTypes
from mhr_api.resources import registration_utils as reg_utils
from mhr_api.resources import utils as resource_utils
from mhr_api.services.authz import get_group, is_all_staff_account, is_bcol_help, is_staff
from mhr_api.services.authz import get_group, is_all_staff_account, is_bcol_help, is_sbc_office_account, is_staff
from mhr_api.services.payment import TransactionTypes
from mhr_api.services.payment.exceptions import SBCPaymentException
from mhr_api.utils.auth import jwt
Expand Down Expand Up @@ -73,7 +73,14 @@ def post_admin_registration(mhr_number: str): # pylint: disable=too-many-return
return resource_utils.unauthorized_error_response(account_id)
# Not found throws exception.
current_reg: MhrRegistration = MhrRegistration.find_all_by_mhr_number(mhr_number, account_id, True)
if not is_all_staff_account(account_id) and doc_type == MhrDocumentTypes.CANCEL_PERMIT:
is_all_staff: bool = is_staff(jwt) or is_all_staff_account(account_id)
if (
not is_all_staff
and doc_type == MhrDocumentTypes.CANCEL_PERMIT
and is_sbc_office_account(jwt.get_token_auth_header(), account_id, jwt)
):
is_all_staff = True
if not is_all_staff and doc_type == MhrDocumentTypes.CANCEL_PERMIT:
can_edit: bool = False
if current_reg.change_registrations:
for reg in current_reg.change_registrations:
Expand All @@ -100,7 +107,6 @@ def post_admin_registration(mhr_number: str): # pylint: disable=too-many-return
# Validate request against the schema.
valid_format, errors = schema_utils.validate(request_json, "adminRegistration", "mhr")
# Additional validation not covered by the schema.
is_all_staff: bool = is_staff(jwt) or is_all_staff_account(account_id)
extra_validation_msg = resource_utils.validate_admin_registration(current_reg, request_json, is_all_staff)
if not valid_format or extra_validation_msg != "":
return resource_utils.validation_error_response(errors, reg_utils.VAL_ERROR, extra_validation_msg)
Expand Down
3 changes: 2 additions & 1 deletion mhr-api/src/mhr_api/resources/v1/registrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
is_all_staff_account,
is_bcol_help,
is_reg_staff_account,
is_sbc_office_account,
is_staff,
)
from mhr_api.services.document_storage.storage_service import DocumentTypes, GoogleStorageService
Expand Down Expand Up @@ -226,7 +227,7 @@ def get_registrations(mhr_number: str): # pylint: disable=too-many-return-state
)

if current_param and response_json.get("permitStatus", "") == MhrNoteStatusTypes.ACTIVE:
if is_all_staff_account(account_id):
if is_all_staff_account(account_id) or is_sbc_office_account(jwt.get_token_auth_header(), account_id, jwt):
response_json["changePermit"] = True
else:
response_json["changePermit"] = get_change_permit(registration, account_id)
Expand Down
97 changes: 59 additions & 38 deletions ppr-api/.env.sample
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
# third party Services
#SENTRY_DSN=
#CODECOV_TOKEN=
#LD_SDK_KEY=
DEPLOYMENT_PLATFORM=
DEPLOYMENT_ENV=
DEPLOYMENT_PROJECT=
TRACING_ENABLE=

# Registry Integration Services
PAYMENT_SVC_URL=
#AUTH_SVC_URL=
AUTH_SVC_URL=
#REPORT_SVC_URL=
REPORT_SVC_URL=

# Flask shite
FLASK_ENV=development
FLASK_APP=wsgi.py
SECRET=some md5 hash
APP_SETTINGS=dev
LD_SDK_KEY=

# SQL Alchemy
DATABASE_USERNAME=
Expand All @@ -23,20 +12,13 @@ DATABASE_NAME=
DATABASE_HOST=
DATABASE_PORT=

## TEST DB
## UNIT TEST/CI DB
DATABASE_TEST_USERNAME=
DATABASE_TEST_PASSWORD=
DATABASE_TEST_NAME=
DATABASE_TEST_HOST=localhost
DATABASE_TEST_PORT=5432

# ## NATS - STAN
NATS_SERVERS=nats://localhost:4222
NATS_CLIENT_NAME=entity.legal_api
NATS_CLUSTER_ID=test-cluster
NATS_FILER_SUBJECT=entity.filing.filer
NATS_QUEUE=entity-filer-worker

# JWT Settings
JWT_OIDC_WELL_KNOWN_CONFIG=
JWT_OIDC_ALGORITHMS=RS256
Expand All @@ -45,21 +27,60 @@ JWT_OIDC_CLIENT_SECRET=
JWT_OIDC_CACHING_ENABLED=True
JWT_OIDC_JWKS_CACHE_TIMEOUT=300

# Service Accounts
# Accounts
ACCOUNT_SVC_URL=
JWT_OIDC_TEST_ISSUER=
JWT_OIDC_TEST_WELL_KNOWN_CONFIG=
JWT_OIDC_TEST_ALGORITHMS=RS256
JWT_OIDC_TEST_AUDIENCE=
JWT_OIDC_TEST_CLIENT_SECRET=
JWT_OIDC_TEST_CACHING_ENABLED=True
JWT_OIDC_TEST_JWKS_CACHE_TIMEOUT=300
JWT_OIDC_PUBLIC_KEY_PEM=

# Integration Settings
AUTH_SVC_URL=
PAYMENT_SVC_URL=
PAYMENT_GATEWAY_APIKEY_TEST=
REPORT_SVC_URL=
REPORT_TEMPLATE_PATH="report-templates"
REPORT_API_AUDIENCE=
REPORT_VERSION="2"
GATEWAY_URL=
SUBSCRIPTION_API_KEY=

# Service account for payment refunds
ACCOUNT_SVC_CLIENT_ID=
ACCOUNT_SVC_CLIENT_SECRET=
ACCOUNT_SVC_TIMEOUT=20

# ## MVP Settings
GO_LIVE_DATE=2019-08-12
# DB Query limits on result set sizes
ACCOUNT_REGISTRATIONS_MAX_RESULTS="100"
ACCOUNT_DRAFTS_MAX_RESULTS="10"
ACCOUNT_SEARCH_MAX_RESULTS="1000"

# DEBTOR search trigram similarity quotients
SIMILARITY_QUOTIENT_BUSINESS_NAME="0.6"
SIMILARITY_QUOTIENT_FIRST_NAME="0.4"
SIMILARITY_QUOTIENT_LAST_NAME="0.29"
SIMILARITY_QUOTIENT_DEFAULT="0.5"
# Maximum length of search results for real time report generation.
MAX_SIZE_SEARCH_RT="200000"
# Number of registrations threshold for large search report format.
REPORT_SEARCH_LIGHT="700"
SEARCH_PDF_ASYNC_THRESHOLD="75"
EVENT_MAX_RETRIES="3"

# Cloud Settings
GOOGLE_DEFAULT_SA=
GCP_CS_SA_SCOPES=
GCP_CS_BUCKET_ID=
GCP_CS_BUCKET_ID_VERIFICATION=
GCP_CS_BUCKET_ID_REGISTRATION=
GCP_CS_BUCKET_ID_MAIL=
GCP_PS_PROJECT_ID=
GCP_PS_SEARCH_REPORT_TOPIC=
GCP_PS_NOTIFICATION_TOPIC=
GCP_PS_VERIFICATION_REPORT_TOPIC=
GCP_PS_REGISTRATION_REPORT_TOPIC=

# ## INTEGRATION TESTS
#RUN_AFFILIATION_TESTS=True
#TEST_NATS_DOCKER=True
#RUN_COLIN_TESTS=True
#RUN_NATS_TESTS=True
#RUN_PAYMENT_TESTS=True
#RUN_AUTHORIZATION_TESTS=True
NOT_GITHUB_CI=True
# Host name/IP of mail out service for file transfer: only in TEST and PROD.
SURFACE_MAIL_HOST=''
SURFACE_MAIL_TARGET_PATH='FIN_PPR/TEST'
88 changes: 73 additions & 15 deletions ppr-api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,34 +1,92 @@
FROM python:3.11-buster
FROM python:3.12-bullseye AS development_build

USER root

ARG VCS_REF="missing"
ARG BUILD_DATE="missing"

ENV VCS_REF=${VCS_REF}
ENV BUILD_DATE=${BUILD_DATE}
ENV PORT=8080

LABEL org.label-schema.vcs-ref=${VCS_REF} \
org.label-schema.build-date=${BUILD_DATE}

# Create working directory
RUN mkdir /opt/app-root && chmod 755 /opt/app-root
WORKDIR /opt/app-root
LABEL maintainer="thorwolpert"
LABEL vendor="BCROS"

ARG APP_ENV \
# Needed for fixing permissions of files created by Docker:
UID=1000 \
GID=1000

ENV APP_ENV=${APP_ENV} \
# python:
PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PYTHONDONTWRITEBYTECODE=1 \
# pip:
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_DEFAULT_TIMEOUT=100 \
PIP_ROOT_USER_ACTION=ignore \
# poetry:
POETRY_VERSION=1.8.3 \
POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_CREATE=false \
POETRY_CACHE_DIR='/var/cache/pypoetry' \
POETRY_HOME='/usr/local'

SHELL ["/bin/bash", "-eo", "pipefail", "-c"]

RUN apt-get update && apt-get upgrade -y \
&& apt-get install --no-install-recommends -y \
bash \
brotli \
build-essential \
curl \
gettext \
git \
libpq-dev \
wait-for-it \
&& curl -sSL 'https://install.python-poetry.org' | python - \
&& poetry --version \
# Cleaning cache:
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*

WORKDIR /code

RUN groupadd -g "${GID}" -r web \
&& useradd -d '/code' -g web -l -r -u "${UID}" web \
&& chown web:web -R '/code'

# Install the requirements
COPY ./requirements.txt .
# Copy only requirements, to cache them in docker layer
COPY --chown=web:web ./poetry.lock ./pyproject.toml /code/

RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=web:web ./src /code/src
COPY --chown=web:web ./README.md /code

COPY . .
# Project initialization:
RUN --mount=type=cache,target="$POETRY_CACHE_DIR" \
echo "$APP_ENV" \
&& poetry version \
# Install deps:
&& poetry run pip install -U pip \
&& poetry install \
$(if [ -z ${APP_ENV+x} ] | [ "$APP_ENV" = 'production' ]; then echo '--only main'; fi) \
--no-interaction --no-ansi

RUN pip install .
# Running as non-root user:
USER web

USER 1001
# The following stage is only for production:
FROM development_build AS production_build
COPY --chown=web:web . /code

# Run the server
ENV PYTHONPATH=/opt/app-root/src
# ENV PYTHONPATH=/opt/app-root/src

EXPOSE 8080
# CMD gunicorn --bind 0.0.0.0:${PORT} --config /code/gunicorn_config.py wsgi:app

CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--config", "/opt/app-root/gunicorn_config.py", "wsgi:application"]
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 wsgi:app
Loading
Loading