Projects portfolio for the Mapping and Geographic Information Centre (MAGIC) at the British Antarctic Survey.
View Portfolio (Restricted, MAGIC).
Note: This project is designed to meet an internal need within MAGIC. It has been open-sourced in case it's of use to others with similar needs.
This project is a mature alpha. After some real world testing it will progress to a beta and if successful, a live, production, service.
Whilst an alpha, there are significant performance limitations, partially complete features, and general rough edges.
This project is intended to help people understand the things MAGIC are working on, at a relatively high 'project' level. In addition, this Portfolio shows:
- how these projects relate to the Strategic Objectives and Activity Areas defined in the MAGIC Strategy (Internal).
- how MAGIC team members relate to these projects
- the status of each project (proposal, complete, historic, etc.)
- links to more in-depth/detailed information about each project (e.g. proposal documents/plans, specifications, etc.)
These links could include information held in:
- other BAS tools - such as the Digital Workspace, RMS, GitLab, etc.
- external websites - such as UKRI Gateway to Research, ESA funding database, etc.
The audience for this Portfolio is:
- MAGIC team leaders
- MAGIC team members
- other BAS staff (? #34 (Internal))
- the public (? #15 (Internal))
Note: You need permission to view projects to complete this task. See the Access Control section for more information.
- visit the MAGIC Projects Portfolio
- click the Sign in to Continue button
- if prompted, sign in to your BAS/NERC account (i.e. the account you use for your BAS email)
- if promoted, allow the Projects Portfolio to access your basic profile information (only needed once)
Note: You need permission to view projects and change projects to complete this task. See the Access Control section for more information.
- follow the steps to View Projects to access and sign in to the Projects Portfolio
- click the green Add Project button in the top right
- complete the web-form as directed
Note: You need permission to access the backend database to complete this task. See the Access Control section for more information.
- visit the MAGIC Projects Portfolio database [Airtable]
- select the relevant table with the
(V2)prefix (consult the 'Data Model (V2)' if unsure which table to edit) - make adjustments as needed
Note: You need permission to view projects and change projects to complete this task. See the Access Control section for more information.
- follow the steps to View Projects to access and sign in to the Projects Portfolio
- click the name of the project to be deleted
- on the project details page, click the Delete Project button from the bottom of the sidebar to the right
Note: You need permission to view projects and change projects to complete this task. See the Access Control section for more information.
- follow the steps to View Projects to access and sign in to the Projects Portfolio
- click the name of the project to be deleted
- on the project details page, click the Add Role button from the bottom of the sidebar to the right
- complete the web-form as directed
Note: You need permission to access the backend database to complete this task. See the Access Control section for more information.
- follow the steps to Edit Projects to access Projects Portfolio database
- choose the Project Roles (V2) table
- remove the relevant row associating a person with a project
See #28 for making this task self-service.
Note: You need permission to view projects and change projects to complete this task. See the Access Control section for more information.
- follow the steps to View Projects to access and sign in to the Projects Portfolio
- click the name of the project to be deleted
- on the project details page, click the Add Link button from the bottom of the sidebar to the right
- complete the web-form as directed
Note: You need permission to view projects and change projects to complete this task. See the Access Control section for more information.
- follow the steps to View Projects to access and sign in to the Projects Portfolio
- click the name of the project to be deleted
- on the project details page, for the relevant link, select the broken link icon shown to the right of the sidebar
Different permissions are required to access or change projects within the Portfolio website, and/or the backend database, summarised in the table below:
| Permission | Role (Azure) | Role (Airtable) | Assigned To |
|---|---|---|---|
| view projects | BAS.MAGIC.Portfolio.Projects.Read.All |
N/A | MAGIC team members |
| change projects | BAS.MAGIC.Portfolio.Projects.Write.All |
N/A | MAGIC team members |
| access the backend database | N/A | Editor | Specific Individuals |
In most circumstances, only the view projects and change projects permissions are required to use the Projects Portfolio. These permissions are assigned to all MAGIC team members (using the central MAGIC security group (internal)).
The access the backend database permission is only needed to access, and update, the backend Airtable database. This is not normally needed, and is informally restricted to system administrators. To request permission, please contact @felnne.
Airtable is used as a database and application backend. This tool was chosen so that the application Data Model can iterated quickly, as it offers a pre-built admin UI, data entry forms and API for accessing information.
A Flask application, hosted in the DigitalOcean App Platform, is used as a frontend application. This tool was chosen to give greater control over how projects are displayed and to allow the backend to be changed in the future without end-users being aware.
The Flask frontend communicates with the Airtable backend using the Airtable API dynamically at runtime. Microsoft Azure is used to enforce permissions in the Flask frontend. Airtable permissions are used to control access to the backend.
The data model for this application is held in Airtable, specifically in these tables:
There have been multiple versions/iterations of this data model. The current revision is V2.
Projects represent activities and are the main entity in the data model, other entities relate to back to projects.
People represent individuals (MAGIC team members), they consist of a name and ORCID iD.
Project links represent URLs associated with a project (e.g. a link to project's grant proposal or GitLab project).
Project links have a type so the frontend can understand the system it links to. This functionality is not yet used.
Project roles represent which people are associated with which projects. These associations are contextual (e.g. project leader or member).
A series of Jinja2 templates are used for rendering pages in the website component.
Templates use the BAS Style Kit Jinja Templates.
Feedback forms point to the project issue tracker in GitLab, as we are not expecting feedback from externals.
The DigitalOcean App Platform is used to run this application. The app platform manages deploying and running the Flask frontend.
This was chosen partly to prove and understand the features this platform offers (for use in other projects), and to avoid spending time setting up and configuring infrastructure (as this project's usefulness is still unproven).
The App Platform automatically builds and deploys a container for running the Flask frontend using
Cloud Native Buildpacks. For this application, the Python buildpack is used, with the
provisioning/do-app-platform/requirements.txt requirements file
used as an input. This requirements file depends on the Application Python Package.
As the App Platform only supports source code repositories located in Github.com or GitLab.com, it is necessary to mirror the repository from the BAS GitLab instance to GitLab.com. This is automatic using GitLab's repo mirroring.
Not yet configured, see #35 (Internal).
Logs for the website component are written to stdout/stderr as appropriate. In the DigitalOcean App Platform, logs can be accessed through the DigitalOcean console.
For the frontend Flask application, Microsoft Azure's OAuth functionality is used with Active Directory user accounts from the NERC tenancy.
For the backend Airtable database, Airflow's native permissions system is used with Airtable accounts.
The Projects Portfolio is registered as an Azure App Registration with an associated security principle.
App Roles are defined within this app registration for the different permissions listed in the Access Control section (specifically the 'Role (Azure)' column). These permissions are associated with the users and groups as required through the security principle. Additional ID token claims for the user's name and email address are used for personalisation. The app registration, roles, claims and other configuration options are defined as code using Terraform.
The MSAL for Python library is used to implement the OAuth authorisation code grant in the Flask frontend. App roles and optional claims are included as claims in the ID token returned by this grant, stored in the browser session. The roles claim is checked by methods in the frontend app to verify permissions.
Application configuration options for the Flask frontend are set using environment variables in the DigitalOcean App Spec in Terraform.
Note: In Development Environments, environment variables are set using a local .env
file.
| Configuration Option | Description | Example Value |
|---|---|---|
FLASK_APP |
Entry point to Flask application | bas_magic_projects_portfolio.app |
FLASK_ENV |
Flask environment name | production |
FLASK_SESSION_KEY |
Encryption key used to secure Flask sessions | 65682e1a8e545f881b38c14e9bcfba9cfc0cdd1151479b88 [1] |
AIRTABLE_KEY |
Airtable API key | keyrD2ea764604m6uQ |
AIRTABLE_BASE |
Airtable Base ID | appKn6jdVjvP75eUC |
AUTH_CLIENT_ID |
Azure App Registration client ID | 44a4edf5-0a30-473d-838e-6bdfb4178c0c [2] |
AUTH_CLIENT_SECRET |
Azure App Registration client secret | JgxIzLfbV5j.jJ0s~HNDib_Mbs72nA-3x1 [3] |
AUTH_CLIENT_TENANCY |
Azure tenancy containing the App Registration | https://login.microsoftonline.com/b311db95-32ad-438f-a101-7ba061712a4e [2] |
[1] Generate with python3 -c 'import os; print(os.urandom(24).hex())', see the
Flask quick start for more information.
[2] Retrieve these details from the Azure Portal for the application registration for this project.
[3] Generate through the Azure Portal, see the Microsoft documentation for more information.
Configuration options for Flask's session are hard-coded within the application. Their effect is to use permanent sessions with the fixed duration of 12 hours - meaning users will need to re-authenticate at least every 12 hours.
Terraform resources are defined in provisioning/terraform/terraform.tf.
Terraform is used for configuring:
- the GitLab project in GitLab.com as a deployment source for the DigitalOcean App Platform
- the DigitalOcean App Platform application
- the Microsoft Azure App Registration (including app roles and claims)
Access to the BAS DigitalOcean account and NERC Azure Tenancy are required to provision these resources. Docker and Docker Compose are required to run the Terraform binary required for resources in this project.
Note: This Terraform configuration needs to be applied in stages, as resources need to be manually configured before others are created. See the numbered steps in the commands below:
# step 1 - create Terraform container (includes Azure CLI client)
$ cd provisioning/terraform
$ docker-compose run terraform
# step 2 - setup Terraform and ensure syntax is valid and formatting normalised
$ terraform init
$ terraform validate
$ terraform fmt
# step 3 - sign in to Azure CLI to allow access to Azure managed resources
$ az login --allow-no-subscriptions
# step 4 - create Azure resources
$ terraform apply --target azuread_application.magic_projects_portfolio
$ terraform apply --target azuread_service_principal.magic_projects_portfolio
# step 5 - configure Azure resources (see manual steps section)
# step 6 - create the GitLab mirror repository
$ terraform apply --target gitlab_project.magic_projects_portfolio_mirror
$ terraform apply --target gitlab_deploy_token.magic_projects_portfolio_mirror_do_app
# step 7 - configure repository mirroring (see manual steps section)
# step 8 - set DigitalOcean encrypted variables to initial cleartext values (see notes in terraform.tf)
# step 9 - create DigitalOcean app
$ terraform apply --target digitalocean_app.magic_projects_portfolio
# step 10 - retrieve ciphertext values for encrypted env variables from spec in DigitalOcean console
# and update configuration to match
# step 11 - ensure all changes are in sync (Terraform should report no changes will be made)
$ terraform plan
# step 12 - if ok, apply configuration to update state
$ terraform apply
# step 13 - quit and remove Terraform container
$ exit
$ docker-compose downTo configure the app registration:
- login to the Azure Portal and select Azure Active Directory -> App registrations
- select the app registration representing this project
- select the Branding page:
- set the Logo to the project avatar from
- set the Homepage to the Flask frontend endpoint
- set the Publisher domain to bas.ac.uk
- select the Certificates & secrets page and click the New client secret button:
- set the Description to:
app - set Expires to: 24 months
- set the Description to:
- select the Manifest page:
- set the
accessTokenAcceptedVersionproperty to:2
- set the
Once complete, copy the relevant client ID, secret and tenancy endpoint from the app registration for use in settings.
To configure the service principle (app roles):
- login to the Azure Portal and select Azure Active Directory -> Enterprise applications
- select the app registration representing this project (hint: search by application ID, name is unreliable)
- select the Properties page:
- set User assignment required? to: Yes
- select the Users & groups page and click the Add user/group button:
- for User and groups: click to add selections and search for the
G_BAS_MAGIC_Appgroup - for Select a role: click to add selects and choose
BAS.MAGIC.Portfolio.Projects.Read.All
- for User and groups: click to add selections and search for the
- repeat the previous step, choosing the same group but with the
BAS.MAGIC.Portfolio.Projects.Write.Allrole
Note: If permissions are broadened from just MAGIC, move this section to usage or implementation sections.
- configure repository mirroring between the BAS GitLab instance and the corresponding GitLab.com repository created by Terraform by creating a personal access token in GitLab.com
State information for this project is stored remotely using a Backend.
Specifically the AWS S3 backend as part of the BAS Terraform Remote State project.
Remote state storage will be automatically initialised when running terraform init. Any changes to remote state will
be automatically saved to the remote backend, there is no need to push or pull changes.
Permission to read and/or write remote state information for this project is restricted to authorised users. Contact the BAS Web & Applications Team to request access.
See the BAS Terraform Remote State project for how these permissions to remote state are enforced.
A local Python virtual environment managed by Poetry is used for development.
# install pyenv as per https://github.com/pyenv/pyenv#installation and/or install Python 3.8.x
# install Poetry as per https://python-poetry.org/docs/#installation
# install pre-commit as per https://pre-commit.com/
$ poetry config virtualenvs.in-project true
$ git clone https://gitlab.data.bas.ac.uk/MAGIC/magic-projects-portfolio.git
$ cd magic-projects-portfolio
$ poetry installNote: Use the correct Python Version for this project.
Note: To ensure the correct Python version is used, install Poetry using it's installer, not as a Pip package.
Note: Running poetry config virtualenvs.in-project true is optional but recommended to keep all project components
grouped together.
Note: Read & write access to this source repository is restricted. Contact the project maintainer to request access.
To run a local version of the application:
$ cp .env.example .env
# update .env with valid configuration option values (e.g. replace any `xxx` values)
$ poetry run flask runPython dependencies are managed using Poetry which are recorded in pyproject.toml.
- use
poetry addto add new dependencies (usepoetry add --devfor development dependencies) - use
poetry updateto update all dependencies to latest allowed versions
Ensure the poetry.lock file is included in the project repository.
Dependencies will be checked for vulnerabilities using Safety automatically in Continuous Integration. Dependencies can also be checked manually:
$ poetry export --dev --format=requirements.txt --without-hashes | safety check --stdinAll files should exclude trailing whitespace and include an empty final line.
Python code should be linted using Flake8:
$ poetry run flake8 src testsThis will check various aspects including:
- type annotations (except tests)
- doc blocks (pep257 style)
- consistent import ordering
- code formatting (against Black)
- estimated code complexity
- python anti-patterns
- possibly insecure code (this targets long hanging fruit only)
Python code should follow PEP-8 (except line length), using the Black code formatter:
$ poetry run black src testsThese conventions and standards are enforced automatically using a combination of:
- local Git pre-commit hooks hooks/scripts (Flake8 checks only)
- remote Continuous Integration (all checks)
To run pre-commit hooks manually:
$ pre-commit run --all-filesApplication templates use the Flask application's Jinja environment configured to load templates from:
- the BAS Style Kit Jinja Templates package
- the
src/bas_magic_projects_portfolio/templates/directory
Styles, components and patterns from the BAS Style Kit should be used where possible.
Configuration options for Style Kit Jinja Templates are set in the app.py module, including loading local styles and
scripts defined in static/.
Application views should inherit from the application layout,
app.j2.
includes and
macros should be used to breakdown and reuse content
within views.
Not configured, see #36 (Internal).
All commits will trigger a Continuous Integration process using GitLab's CI/CD platform, configured in .gitlab-ci.yml.
This project is distributed as a Python package, available through the BAS GitLab Python registry, installable using Pip.
Both source and binary (Python wheel) packages are built automatically during Continuous Deployment for all tagged releases.
A shared public access deploy token is used to allow this Python package to installed anonymously:
- username:
anonymous-public-access - password:
PxsyfybkCmKDNYWUXCzs
To install using Pip:
$ python3 -m pip install bas-magic-projects-portfolio --extra-index-url https://anonymous-public-access:PxsyfybkCmKDNYWUXCzs@gitlab.data.bas.ac.uk/api/v4/projects/853/packages/pypi/simpleCommits made against the main branch will be mirrored to the
GitLab.com mirror repository. This includes the
requirements.txt file used to specify which version of the
application Application Python Package is installed. This file should be updated as part of each
Release.
The DigitalOcean App Platform app will be force deployed during Continuous Deployment for all git tags. Force deploys ensure the Deployment Docker Container does not cache build dependencies (i.e. this application).
All tagged commits will trigger a Continuous Deployment process using GitLab's CI/CD platform, configured in
.gitlab-ci.yml.
For all releases:
- create a release branch
- close release in
CHANGELOG.md - bump package version using
poetry version - update
provisioning/do-app-platform/requirements.txtto match package version - push changes, merge the release branch into
mainand tag with version
The maintainer of this project is the BAS Mapping and Geographic Information Centre (MAGIC), they can be contacted at: magic@bas.ac.uk.
This project uses issue tracking, see the Issue tracker for more information.
Note: Read & write access to this issue tracker is restricted. Contact the project maintainer to request access.
© UK Research and Innovation (UKRI), 2020 - 2021, British Antarctic Survey.
You may use and re-use this software and associated documentation files free of charge in any format or medium, under the terms of the Open Government Licence v3.0.
You may obtain a copy of the Open Government Licence at http://www.nationalarchives.gov.uk/doc/open-government-licence/