Merge pull request #35 from cisagov/sspj/proof-of-concept

Tiny bit of Docker
This commit is contained in:
Seamus Johnston 2022-08-11 14:27:00 +00:00 committed by GitHub
commit 2fa2f33c3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 327 additions and 1 deletions

21
LICENSE.md Normal file
View file

@ -0,0 +1,21 @@
# License
As a work of the [United States government](https://www.usa.gov/), this project is in the public domain within the United States of America.
Additionally, we waive copyright and related rights in the work worldwide through the CC0 1.0 Universal public domain dedication.
## CC0 1.0 Universal Summary
This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode).
### No Copyright
The person who associated a work with this deed has dedicated the work to the public domain by waiving all of their rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.
You can copy, modify, distribute, and perform the work, even for commercial purposes, all without asking permission.
### Other Information
In no way are the patent or trademark rights of any person affected by CC0, nor are the rights that other persons may have in the work or in how the work is used, such as publicity or privacy rights.
Unless expressly stated otherwise, the person who associated a work with this deed makes no warranties about the work, and disclaims liability for all uses of the work, to the fullest extent permitted by applicable law. When using or citing the work, you should not imply endorsement by the author or the affirmer.

View file

@ -1,7 +1,26 @@
# .gov documentation
========================
Welcome to .gov! This is a repository to house work on the current .gov site(s).
## Onboarding
TBD
TBD
## Code
Code is located in the [src](./src/) directory.
## Documentation
### Architectural Decision Records
Architectural Decision Records (ADR) are located in [docs/architecture/decisions](./docs/architecture/decisions).
### Product Goals
These are located in [docs/product](./docs/product).
### Research Artifacts
Including some helpful scanning tools. These are located in [docs/research](./docs/research)

View file

@ -0,0 +1,25 @@
# 2. Docker for development
Date: 2022-08-09
## Status
Accepted
## Context
Docker is widely accepted at TTS currently and in the development community at large. It works well with cloud.gov and is very portable to other cloud solutions.
The [Federal Audit Clearinghouse](https://github.com/GSA-TTS/FAC) project is a similar project to ours, from which we are taking many examples for reuse. FAC uses Docker.
Other options include using virtual machines or installing dependencies directly onto the host system. The first is not widely used at TTS; the second tends to cause problems with dependency management.
## Decision
To include a Dockerfile and docker-compose file.
## Consequences
We intend to deploy using containerized images; therefore, use of Docker on local will give the closest approximation to higher environments.
A greater technical burden may be placed on new employees during onboarding, if they have not already installed Docker and learned to use it.

View file

@ -0,0 +1,35 @@
# 3. Django
Date: 2022-08-09
## Status
Accepted
## Context
Django is a web framework based on Python that has been in active development since 2005.
It follows a very standard MVC architecture (made popular by Ruby on Rails), although in Django parlance, a “view” is a controller (whereas the views are “templates”).
It comes with a robust object relational mapper for database access and includes a built-in admin interface suitable for simple use cases.
The [Federal Audit Clearinghouse](https://github.com/GSA-TTS/FAC) project is a similar project to ours, from which we are taking many examples for reuse. FAC uses Django.
Numerous other web frameworks exist in many languages, such as Ruby, PHP, Perl, Go, Elixir, etc. Other web frameworks exist in Python, such as Twisted and Flask.
## Decision
To use Django.
## Consequences
Django is well documented and approachable, even for people with limited programming experience.
We will have a dependency on the health of the Django project and the Python ecosystem at large.
Python is an interpreted language and will not have the same performance as compiled languages. Django is slower than its less featureful Python competitors (while being faster than Ruby on Rails, its nearest other-language competitor).
The job market for Django developers is currently (8/2022) strong, with 7,000 open positions on a popular career site.
Moving away from Django at a future point would require a complete rewrite of the codebase.

View file

@ -0,0 +1,29 @@
# 4. Docker base image
Date: 2022-08-09
## Status
Accepted
## Context
In containerized builds, it is rare to start from scratch. The projects Dockerfile should specify a base image from which to build.
The [python page on Docker Hub](https://hub.docker.com/_/python) has a discussion of what various image variants contain.
Python images can be scoped to specific versions, such as 3.8.6, or to more generic versions, such as 3. There is a slim variant for smaller image size and variants scoped to specific versions of Debian.
Alpine is a popular base image due to its small size and fast build times. However, it may not be the best choice for Python projects, due to its use of musl over glibc. Heres a [blog post explaining this](https://pythonspeed.com/articles/alpine-docker-python/).
## Decision
To use python:3.
## Consequences
The python:3 image may or may not be secure enough for the long term needs of the project.
Using python:3 ensures that minor version upgrades will be automatically performed each time the image is built. The consequence is that the code may break unexpectedly, if a minor version introduces an incompatibility. The risk of this is low, as the Python team strives for semantic versioning, but is not zero.
Likewise, not pinning to the underlying Debian release ensures that the image will use the latest stable release at each build, with the same risk and benefit trade-off.

View file

@ -0,0 +1,25 @@
# 5. PostgreSQL
Date: 2022-08-09
## Status
Accepted
## Context
Our choices of which database engine to use are presently limited by our desire to use cloud.gov for deployment.
Cloud.gov supports MySQL, PostgreSQL, and Oracle.
Oracle may be subject to licensing fees.
## Decision
To use PostgreSQL.
## Consequences
All three options are approximately equally capable. The number of CVEs filed against each project differs, but not by any order of magnitude.
The advanced administrative features of each database are not available in cloud.gov, so there is little reason to prefer one option over any other.

9
src/Dockerfile Normal file
View file

@ -0,0 +1,9 @@
FROM python:3
RUN apt-get update && apt-get install -y postgresql-client
COPY Pipfile Pipfile
COPY Pipfile.lock Pipfile.lock
RUN pip install pipenv
RUN pipenv install --system --dev

8
src/Pipfile Normal file
View file

@ -0,0 +1,8 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
django = "*"

43
src/Pipfile.lock generated Normal file
View file

@ -0,0 +1,43 @@
{
"_meta": {
"hash": {
"sha256": "8b5635a4f7b069ae6661115b9eaa15466f7cd96794af5d131735a3638be101fb"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"asgiref": {
"hashes": [
"sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4",
"sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"
],
"markers": "python_version >= '3.7'",
"version": "==3.5.2"
},
"django": {
"hashes": [
"sha256:031ccb717782f6af83a0063a1957686e87cb4581ea61b47b3e9addf60687989a",
"sha256:032f8a6fc7cf05ccd1214e4a2e21dfcd6a23b9d575c6573cacc8c67828dbe642"
],
"index": "pypi",
"version": "==4.1"
},
"sqlparse": {
"hashes": [
"sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae",
"sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"
],
"markers": "python_version >= '3.5'",
"version": "==0.4.2"
}
},
"develop": {}
}

21
src/README.md Normal file
View file

@ -0,0 +1,21 @@
# Registrar
========================
## Development
If you're new to Django, see [Getting Started with Django](https://www.djangoproject.com/start/) for an introduction to the framework.
### Local Setup
* Install Docker <https://docs.docker.com/get-docker/>
* Initialize the application:
```shell
docker-compose build
```
* Run the server: `docker-compose up`
### Update Dependencies
1. Check the [Pipfile](./src/Pipfile) for pinned dependencies and manually adjust the version numbers
1. Run `docker-compose up` and `docker-compose exec app pipenv update` to perform the upgrade and generate a new [Pipfile.lock](./src/Pipfile.lock)

View file

@ -0,0 +1,56 @@
#! /usr/bin/env python
"""
This is a Docker entrypoint that configures the container to run
as the same uid of the user on the host container, rather than
the Docker default of root. Aside from following security best
practices, this makes it so that any files created by the Docker
container are also owned by the same user on the host system.
"""
import sys
import os
import pwd
import subprocess # nosec
HOST_UID = os.stat("/app").st_uid
HOST_USER = "james"
def does_username_exist(username):
try:
pwd.getpwnam(username)
return True
except KeyError:
return False
def does_uid_exist(uid):
try:
pwd.getpwuid(uid)
return True
except KeyError:
return False
if __name__ == "__main__":
if HOST_UID != os.geteuid():
if not does_uid_exist(HOST_UID):
username = HOST_USER
while does_username_exist(username):
username += "0"
home_dir = "/home/%s" % username
subprocess.check_call(
[ # nosec
"useradd",
"-d",
home_dir,
"-m",
username,
"-u",
str(HOST_UID),
]
)
os.environ["HOME"] = "/home/%s" % pwd.getpwuid(HOST_UID).pw_name
os.setuid(HOST_UID)
os.execvp(sys.argv[1], sys.argv[1:]) # nosec

35
src/docker-compose.yml Normal file
View file

@ -0,0 +1,35 @@
version: "3.0"
services:
app:
build: .
volumes:
- ./app:/app
links:
- db
working_dir: /app
entrypoint: python /app/docker_entrypoint.py
deploy:
restart_policy:
condition: on-failure
max_attempts: 5
environment:
# Ensure stdout and stderr are sent straight to the terminal without buffering
- PYTHONUNBUFFERED=yup
# In case we'd like to know
- RUNNING_IN_DOCKER=yup
# How to connect to Postgre container
- DATABASE_URL=postgres://user:feedabee@db/app
# Run in development mode on our local
- DJANGO_SETTINGS_MODULE=app.settings.dev
stdin_open: true
tty: true
ports:
- "8000:8000"
command: "python"
db:
image: postgres:latest
environment:
- POSTGRES_DB=app
- POSTGRES_USER=user
- POSTGRES_PASSWORD=feedabee