mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-04 17:01:56 +02:00
commit
5e4c44a444
27 changed files with 951 additions and 15 deletions
42
.github/workflows/deploy.yaml
vendored
Normal file
42
.github/workflows/deploy.yaml
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
name: Build and deploy
|
||||
|
||||
# This workflow runs on pushes to main (typically,
|
||||
# a merged pull request) and on pushes of tagged commits.
|
||||
|
||||
# Pushes to main will deploy to Unstable; tagged commits
|
||||
# will deploy to Staging
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
tags:
|
||||
- v*
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy-unstable:
|
||||
# if this job runs on a branch, we deduce that code
|
||||
# has been pushed to main and should be deployed to unstable
|
||||
if: ${{ github.ref_type == 'branch' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Deploy to cloud.gov sandbox
|
||||
uses: 18f/cg-deploy-action@main
|
||||
env:
|
||||
DEPLOY_NOW: thanks
|
||||
with:
|
||||
cf_username: ${{ secrets.CF_USERNAME }}
|
||||
cf_password: ${{ secrets.CF_PASSWORD }}
|
||||
cf_org: sandbox-gsa
|
||||
cf_space: dotgov-poc
|
||||
push_arguments: "-f ops/manifests/manifest-unstable.yaml"
|
||||
|
||||
# deploy-staging:
|
||||
# # if this job runs on a tag, we deduce that code
|
||||
# # has been tagged for release and should be deployed to staging
|
||||
# if: ${{ github.ref_type == 'tag' }}
|
34
.github/workflows/migrate.yaml
vendored
Normal file
34
.github/workflows/migrate.yaml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
name: Run Migrations
|
||||
|
||||
# This workflow can be run from the CLI
|
||||
# gh workflow run migrate.yaml -f environment=sandbox
|
||||
# OR
|
||||
# cf run-task getgov-unstable --wait \
|
||||
# --command 'python manage.py migrate' --name migrate
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
type: choice
|
||||
description: Where should we run migrations
|
||||
options:
|
||||
- unstable
|
||||
- staging
|
||||
|
||||
jobs:
|
||||
migrate-unstable:
|
||||
if: ${{ github.event.inputs.environment == 'unstable' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Django migrations for unstable
|
||||
uses: 18f/cg-deploy-action@main
|
||||
with:
|
||||
cf_username: ${{ secrets.CF_USERNAME }}
|
||||
cf_password: ${{ secrets.CF_PASSWORD }}
|
||||
cf_org: sandbox-gsa
|
||||
cf_space: dotgov-poc
|
||||
full_command: "cf run-task getgov-unstable --wait --command 'python manage.py migrate' --name migrate"
|
||||
|
||||
# migrate:
|
||||
# if: ${{ github.event.inputs.environment == 'staging' }}
|
151
.gitignore
vendored
151
.gitignore
vendored
|
@ -1 +1,150 @@
|
|||
docs/research/data/**
|
||||
### Project specific ###
|
||||
|
||||
docs/research/data/**
|
||||
static/
|
||||
credentials*
|
||||
|
||||
### The usual garbage files ###
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
.idea/
|
||||
|
||||
# Node
|
||||
node_modules
|
||||
|
|
30
docs/architecture/decisions/0007-python-buildpack.md
Normal file
30
docs/architecture/decisions/0007-python-buildpack.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# 7. Python Buildpack
|
||||
|
||||
Date: 2022-08-12
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
We had previously drafted ADRs to use Docker to build images for containerized deployment. The motivation was to reduce dependency on Cloud.gov. These ADRs were rejected, mainly owing to the necessity of having an image repository to hold the built images. The team had concerns about an overreliance on GitHub with their GitHub Packages service and about the overall maintenance burden of any image repository.
|
||||
|
||||
Cloud.gov uses Cloud Foundry which provides several “buildpacks”. These are automated environments which will take a code repository of a certain language and do the usual setup steps to prepare a deployment of that code. In the case of Python, this means automated detection of Pipfile and installation of packages.
|
||||
|
||||
We do not anticipate needing a custom buildpack, because our current use case falls completely within the Python buildpack's purview.
|
||||
|
||||
## Decision
|
||||
|
||||
To use Cloud Foundry’s Python buildpack.
|
||||
|
||||
## Consequences
|
||||
|
||||
There will be a small amount of future work if the code is migrated off of Cloud.gov, but only a small amount. Proportionate to the overall effort of migration, it is inconsequential.
|
||||
|
||||
Cloud.gov provides [documentation around the trade-offs](https://cloud.gov/docs/deployment/docker/):
|
||||
|
||||
| | Supported buildpack | Docker container |
|
||||
|---|---|---|
|
||||
|Pros|It “just works”. Automatic and constant security updates. All you need to do is write code.|Can build container images and run containers on local workstation. Fine-grained control over compilation and root filesystem.|
|
||||
|Cons|Difficult to recreate the execution environment locally. Testing compilation and the result of staging is harder.|Added responsibility for all security updates and bug fixes. More compliance responsibility means more work.|
|
25
docs/architecture/decisions/0008-server-side-rendering.md
Normal file
25
docs/architecture/decisions/0008-server-side-rendering.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# 8. Server Side Rendering
|
||||
|
||||
Date: 2022-08-16
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
In deciding how content would be delivered to the end user, we held a meeting with Engineering and Design ~and the mayor of Igorville~ [^1] and consulted the [18F Engineering Practices Guide](https://engineering.18f.gov/web-architecture/).
|
||||
|
||||
The two major options considered were 1) a single page application, developed with a JavaScript framework such as React, perhaps served from its own Node-based server or a static file host such as Federalist; or 2) traditional server rendered HTML pages, delivered by Django, accompanied by a small amount of JavaScript and CSS.
|
||||
|
||||
## Decision
|
||||
|
||||
To use server-side rendering performed by Django.
|
||||
|
||||
## Consequences
|
||||
|
||||
The positive aspects of this include: easier state management, fewer bugs caused by stale cache data, easier 508 compliance for disabled users, better maintainability for future developers due to fewer dependencies and a shallower learning curve, and better cross browser compatibility.
|
||||
|
||||
The risks to this approach are given by the frontend lead on a sister 18F project: a less well-developed API since this approach does not require an API upfront, users/stakeholders attempting to request ever increasing levels of interactivity, and familiarity with vanilla.js has waned over the years.
|
||||
|
||||
[^1]: Inside joke. To obtain access to the registrant flow, a member of our team signed up for .gov using the fictitious town of Igorville.
|
41
docs/architecture/diagrams/request.dot
Normal file
41
docs/architecture/diagrams/request.dot
Normal file
|
@ -0,0 +1,41 @@
|
|||
digraph sequenceDiagram {
|
||||
# Install graphviz and run `fdp -Tpng request.dot -o request_diagram.png`
|
||||
subgraph cluster_1 {
|
||||
label="Request and Response";
|
||||
browserHead [ label="{Browser|user makes request}" pos="0.1,4.75!" shape="record" ];
|
||||
browserPoint0 [ pos="0.1,4!" shape="point" width="0" ]
|
||||
browserPoint5 [ pos="0.1,0.75!" shape="point" width="0" ]
|
||||
browserFoot [ label="Browser" pos="0,0!" shape="record" ];
|
||||
|
||||
viewHead [ label="{Django Views|business logic applied}" pos="2.5,4.75!" shape="record" ];
|
||||
viewPoint0 [ pos="2.5,4!" shape="point" width="0" ]
|
||||
viewPoint1 [ pos="2.5,3.75!" shape="point" width="0" ]
|
||||
viewPoint2 [ pos="2.5,3.5!" shape="point" width="0" ]
|
||||
viewPoint3 [ pos="2.5,1.25!" shape="point" width="0" ]
|
||||
viewPoint4 [ pos="2.5,1!" shape="point" width="0" ]
|
||||
viewPoint5 [ pos="2.5,0.75!" shape="point" width="0" ]
|
||||
viewFoot [ label="Django view" pos="2.5,0!" shape="record" ];
|
||||
|
||||
databaseHead [ label="{Django ORM|database consulted}" pos="5,4.75!" shape="record" ];
|
||||
databasePoint1 [ pos="5,3.75!" shape="point" width="0" ]
|
||||
databasePoint2 [ pos="5,3.5!" shape="point" width="0" ]
|
||||
databaseFoot [ label="Django ORM" pos="5,2.5!" shape="record" ];
|
||||
|
||||
templateHead [ label="{Django Templates|html response prepared}" pos="5,2.25!" shape="record" ];
|
||||
templatePoint3 [ pos="5,1.25!" shape="point" width="0" ]
|
||||
templatePoint4 [ pos="5,1!" shape="point" width="0" ]
|
||||
templateFoot [ label="Django Templates" pos="5,0!" shape="record" ];
|
||||
|
||||
browserHead -> browserPoint0 -> browserFoot [ dir="none" style="dashed" ]
|
||||
viewHead -> viewPoint0 -> viewFoot [ dir="none" style="dashed" ]
|
||||
databaseHead -> databasePoint1 -> databaseFoot [ dir="none" style="dashed" ]
|
||||
templateHead -> templatePoint3 -> templateFoot [ dir="none" style="dashed" ]
|
||||
|
||||
browserPoint0 -> viewPoint0 [ style="solid" ]
|
||||
viewPoint1 -> databasePoint1 [ style="solid" ]
|
||||
databasePoint2 -> viewPoint2 [ style="solid" ]
|
||||
viewPoint3 -> templatePoint3 [ style="solid" ]
|
||||
templatePoint4 -> viewPoint4 [ style="solid" ]
|
||||
viewPoint5 -> browserPoint5 [ style="solid" ]
|
||||
}
|
||||
}
|
BIN
docs/architecture/diagrams/request_diagram.png
Normal file
BIN
docs/architecture/diagrams/request_diagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
22
docs/architecture/diagrams/system.dot
Normal file
22
docs/architecture/diagrams/system.dot
Normal file
|
@ -0,0 +1,22 @@
|
|||
digraph systemDiagram {
|
||||
# Install graphviz and run `fdp -Tpng system.dot -o system_diagram.png`
|
||||
subgraph cluster_0 {
|
||||
label="System Diagram";
|
||||
node [shape=record];
|
||||
registrant [label="Registrant"];
|
||||
subgraph cluster_cloud {
|
||||
label="cloud.gov";
|
||||
node [shape=record];
|
||||
postgres [label="Postgres Database"];
|
||||
subgraph cluster_django {
|
||||
label="Django MVC";
|
||||
node [shape=record];
|
||||
models [pos="0,1!" label="Database ORM"];
|
||||
views [pos="1,.5!" label="Views"];
|
||||
templates [pos="1,0!" label="Templates"];
|
||||
}
|
||||
}
|
||||
registrant -> views [dir=both];
|
||||
models -> postgres [dir=both];
|
||||
}
|
||||
}
|
BIN
docs/architecture/diagrams/system_diagram.png
Normal file
BIN
docs/architecture/diagrams/system_diagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
59
docs/ops/README.md
Normal file
59
docs/ops/README.md
Normal file
|
@ -0,0 +1,59 @@
|
|||
# Operations
|
||||
========================
|
||||
|
||||
## Authenticating
|
||||
|
||||
You'll need the [Cloud Foundry CLI](https://docs.cloud.gov/getting-started/setup/).
|
||||
|
||||
We use the V7 Cloud Foundry CLI.
|
||||
|
||||
```shell
|
||||
cf login -a api.fr.cloud.gov --sso
|
||||
```
|
||||
|
||||
After authenticating, make sure you are targeting the correct org and space!
|
||||
|
||||
```bash
|
||||
cf spaces
|
||||
cf target -o <ORG> -s <SPACE>
|
||||
```
|
||||
|
||||
## Rotating Environment Secrets
|
||||
|
||||
Secrets were originally created with:
|
||||
|
||||
```sh
|
||||
cf cups getgov-credentials -p credentials-<ENVIRONMENT>.json
|
||||
```
|
||||
|
||||
Where `credentials-<ENVIRONMENT>.json` looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"DJANGO_SECRET_KEY": "EXAMPLE",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
You can see the current environment with `cf env <APP>`, for example `cf env getgov-unstable`.
|
||||
|
||||
The command `cups` stands for [create user provided service](https://docs.cloudfoundry.org/devguide/services/user-provided.html). User provided services are the way currently recommended by Cloud.gov for deploying secrets. The user provided service is bound to the application in `manifest-<ENVIRONMENT>.json`.
|
||||
|
||||
To rotate secrets, create a new `credentials-<ENVIRONMENT>.json` file, upload it, then restage the app.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
cf uups getgov-credentials -p credentials-unstable.json
|
||||
cf restage getgov-unstable --strategy rolling
|
||||
```
|
||||
|
||||
Non-secret environment variables can be declared in `manifest-<ENVIRONMENT>.json` directly.
|
||||
|
||||
## Database
|
||||
|
||||
In sandbox, created with `cf create-service aws-rds micro-psql getgov-database`.
|
||||
|
||||
Binding the database in `manifest-<ENVIRONMENT>.json` automatically inserts the connection string into the environment as `DATABASE_URL`.
|
||||
|
||||
[Cloud.gov RDS documentation](https://cloud.gov/docs/services/relational-database/).
|
6
ops/README.md
Normal file
6
ops/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Operations
|
||||
========================
|
||||
|
||||
This directory contains files related to deploying or running the application(s).
|
||||
|
||||
Documentation is in [docs/ops](../docs/ops).
|
4
ops/manifests/README.md
Normal file
4
ops/manifests/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Manifests
|
||||
========================
|
||||
|
||||
This directory contains files used by the deployment pipeline to deploy to Cloud.gov.
|
23
ops/manifests/manifest-unstable.yaml
Normal file
23
ops/manifests/manifest-unstable.yaml
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
applications:
|
||||
- name: getgov-unstable
|
||||
buildpacks:
|
||||
- python_buildpack
|
||||
path: ../../src
|
||||
instances: 1
|
||||
memory: 512M
|
||||
stack: cflinuxfs3
|
||||
timeout: 180
|
||||
command: gunicorn registrar.config.wsgi -t 60
|
||||
health-check-type: http
|
||||
health-check-http-endpoint: /health
|
||||
env:
|
||||
# Send stdout and stderr straight to the terminal without buffering
|
||||
PYTHONUNBUFFERED: yup
|
||||
# Tell Django where to find its configuration
|
||||
DJANGO_SETTINGS_MODULE: registrar.config.settings
|
||||
routes:
|
||||
- route: getgov-unstable.app.cloud.gov
|
||||
services:
|
||||
- getgov-credentials
|
||||
- getgov-database
|
|
@ -5,4 +5,12 @@ name = "pypi"
|
|||
|
||||
[packages]
|
||||
django = "*"
|
||||
cfenv = "*"
|
||||
django-allow-cidr = "*"
|
||||
django-csp = "*"
|
||||
environs = {extras=["django"]}
|
||||
gunicorn = "*"
|
||||
psycopg2-binary = "*"
|
||||
|
||||
[dev-packages]
|
||||
django-debug-toolbar = "*"
|
225
src/Pipfile.lock
generated
225
src/Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "8b5635a4f7b069ae6661115b9eaa15466f7cd96794af5d131735a3638be101fb"
|
||||
"sha256": "3c3bdeb59b98dcd8c01350c36619ab12b593f8c25846dc3425f481b587fc0ae8"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
|
@ -22,6 +22,28 @@
|
|||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.5.2"
|
||||
},
|
||||
"cfenv": {
|
||||
"hashes": [
|
||||
"sha256:7815bffcc4a3db350f92517157fafc577c11b5a7ff172dc5632f1042b93073e8",
|
||||
"sha256:c7a91a4c82431acfc35db664c194d5e6cc7f4df3dcb692d0f836a6ceb0156167"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.3"
|
||||
},
|
||||
"dj-database-url": {
|
||||
"hashes": [
|
||||
"sha256:ccf3e8718f75ddd147a1e212fca88eecdaa721759ee48e38b485481c77bca3dc",
|
||||
"sha256:cd354a3b7a9136d78d64c17b2aec369e2ae5616fbca6bfbe435ef15bb372ce39"
|
||||
],
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"dj-email-url": {
|
||||
"hashes": [
|
||||
"sha256:64257c4f9d8139a4af8e5267229d32260e433fbf257b0cf8fc855bb0cc39ca7d",
|
||||
"sha256:ef36f8a324ec57cf3be5c7a7ef44ed6900ca0208624a918ab33adc1cf6427b39"
|
||||
],
|
||||
"version": "==1.0.5"
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:031ccb717782f6af83a0063a1957686e87cb4581ea61b47b3e9addf60687989a",
|
||||
|
@ -30,6 +52,172 @@
|
|||
"index": "pypi",
|
||||
"version": "==4.1"
|
||||
},
|
||||
"django-allow-cidr": {
|
||||
"hashes": [
|
||||
"sha256:2fd88ffe697caf0c1d0fd147b88cf44d81282c069bbc475166a2ff1637ad9155",
|
||||
"sha256:d17347e75d6c02864022f52ed608775a5e9ab144d1a82bb40853714f125f5d87"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.0"
|
||||
},
|
||||
"django-cache-url": {
|
||||
"hashes": [
|
||||
"sha256:6cc9901a99a99751f5458aa7de08ce06e48c1441b1a94c9457d78af74fab9a26",
|
||||
"sha256:c4a62634cffc9d636073cef597a44576d67b07660ab2ef1f02b160ee7ecf0e98"
|
||||
],
|
||||
"version": "==3.4.2"
|
||||
},
|
||||
"django-csp": {
|
||||
"hashes": [
|
||||
"sha256:01443a07723f9a479d498bd7bb63571aaa771e690f64bde515db6cdb76e8041a",
|
||||
"sha256:01eda02ad3f10261c74131cdc0b5a6a62b7c7ad4fd017fbefb7a14776e0a9727"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.7"
|
||||
},
|
||||
"environs": {
|
||||
"extras": [
|
||||
"django"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124",
|
||||
"sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==9.5.0"
|
||||
},
|
||||
"furl": {
|
||||
"hashes": [
|
||||
"sha256:5a6188fe2666c484a12159c18be97a1977a71d632ef5bb867ef15f54af39cc4e",
|
||||
"sha256:9ab425062c4217f9802508e45feb4a83e54324273ac4b202f1850363309666c0"
|
||||
],
|
||||
"version": "==2.1.3"
|
||||
},
|
||||
"gunicorn": {
|
||||
"hashes": [
|
||||
"sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e",
|
||||
"sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==20.1.0"
|
||||
},
|
||||
"marshmallow": {
|
||||
"hashes": [
|
||||
"sha256:00040ab5ea0c608e8787137627a8efae97fabd60552a05dc889c888f814e75eb",
|
||||
"sha256:635fb65a3285a31a30f276f30e958070f5214c7196202caa5c7ecf28f5274bc7"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.17.0"
|
||||
},
|
||||
"orderedmultidict": {
|
||||
"hashes": [
|
||||
"sha256:04070bbb5e87291cc9bfa51df413677faf2141c73c61d2a5f7b26bea3cd882ad",
|
||||
"sha256:43c839a17ee3cdd62234c47deca1a8508a3f2ca1d0678a3bf791c87cf84adbf3"
|
||||
],
|
||||
"version": "==1.0.1"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
|
||||
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==21.3"
|
||||
},
|
||||
"psycopg2-binary": {
|
||||
"hashes": [
|
||||
"sha256:01310cf4cf26db9aea5158c217caa92d291f0500051a6469ac52166e1a16f5b7",
|
||||
"sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76",
|
||||
"sha256:090f3348c0ab2cceb6dfbe6bf721ef61262ddf518cd6cc6ecc7d334996d64efa",
|
||||
"sha256:0a29729145aaaf1ad8bafe663131890e2111f13416b60e460dae0a96af5905c9",
|
||||
"sha256:0c9d5450c566c80c396b7402895c4369a410cab5a82707b11aee1e624da7d004",
|
||||
"sha256:10bb90fb4d523a2aa67773d4ff2b833ec00857f5912bafcfd5f5414e45280fb1",
|
||||
"sha256:12b11322ea00ad8db8c46f18b7dfc47ae215e4df55b46c67a94b4effbaec7094",
|
||||
"sha256:152f09f57417b831418304c7f30d727dc83a12761627bb826951692cc6491e57",
|
||||
"sha256:15803fa813ea05bef089fa78835118b5434204f3a17cb9f1e5dbfd0b9deea5af",
|
||||
"sha256:15c4e4cfa45f5a60599d9cec5f46cd7b1b29d86a6390ec23e8eebaae84e64554",
|
||||
"sha256:183a517a3a63503f70f808b58bfbf962f23d73b6dccddae5aa56152ef2bcb232",
|
||||
"sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c",
|
||||
"sha256:1f6b813106a3abdf7b03640d36e24669234120c72e91d5cbaeb87c5f7c36c65b",
|
||||
"sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834",
|
||||
"sha256:2d872e3c9d5d075a2e104540965a1cf898b52274a5923936e5bfddb58c59c7c2",
|
||||
"sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71",
|
||||
"sha256:3303f8807f342641851578ee7ed1f3efc9802d00a6f83c101d21c608cb864460",
|
||||
"sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e",
|
||||
"sha256:3a79d622f5206d695d7824cbf609a4f5b88ea6d6dab5f7c147fc6d333a8787e4",
|
||||
"sha256:404224e5fef3b193f892abdbf8961ce20e0b6642886cfe1fe1923f41aaa75c9d",
|
||||
"sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d",
|
||||
"sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9",
|
||||
"sha256:526ea0378246d9b080148f2d6681229f4b5964543c170dd10bf4faaab6e0d27f",
|
||||
"sha256:53293533fcbb94c202b7c800a12c873cfe24599656b341f56e71dd2b557be063",
|
||||
"sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478",
|
||||
"sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092",
|
||||
"sha256:63638d875be8c2784cfc952c9ac34e2b50e43f9f0a0660b65e2a87d656b3116c",
|
||||
"sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce",
|
||||
"sha256:68641a34023d306be959101b345732360fc2ea4938982309b786f7be1b43a4a1",
|
||||
"sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65",
|
||||
"sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e",
|
||||
"sha256:7af0dd86ddb2f8af5da57a976d27cd2cd15510518d582b478fbb2292428710b4",
|
||||
"sha256:7b1e9b80afca7b7a386ef087db614faebbf8839b7f4db5eb107d0f1a53225029",
|
||||
"sha256:874a52ecab70af13e899f7847b3e074eeb16ebac5615665db33bce8a1009cf33",
|
||||
"sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39",
|
||||
"sha256:8b344adbb9a862de0c635f4f0425b7958bf5a4b927c8594e6e8d261775796d53",
|
||||
"sha256:8fc53f9af09426a61db9ba357865c77f26076d48669f2e1bb24d85a22fb52307",
|
||||
"sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42",
|
||||
"sha256:93cd1967a18aa0edd4b95b1dfd554cf15af657cb606280996d393dadc88c3c35",
|
||||
"sha256:99485cab9ba0fa9b84f1f9e1fef106f44a46ef6afdeec8885e0b88d0772b49e8",
|
||||
"sha256:9d29409b625a143649d03d0fd7b57e4b92e0ecad9726ba682244b73be91d2fdb",
|
||||
"sha256:a29b3ca4ec9defec6d42bf5feb36bb5817ba3c0230dd83b4edf4bf02684cd0ae",
|
||||
"sha256:a9e1f75f96ea388fbcef36c70640c4efbe4650658f3d6a2967b4cc70e907352e",
|
||||
"sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f",
|
||||
"sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba",
|
||||
"sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24",
|
||||
"sha256:b1c8068513f5b158cf7e29c43a77eb34b407db29aca749d3eb9293ee0d3103ca",
|
||||
"sha256:bda845b664bb6c91446ca9609fc69f7db6c334ec5e4adc87571c34e4f47b7ddb",
|
||||
"sha256:c381bda330ddf2fccbafab789d83ebc6c53db126e4383e73794c74eedce855ef",
|
||||
"sha256:c3ae8e75eb7160851e59adc77b3a19a976e50622e44fd4fd47b8b18208189d42",
|
||||
"sha256:d1c1b569ecafe3a69380a94e6ae09a4789bbb23666f3d3a08d06bbd2451f5ef1",
|
||||
"sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667",
|
||||
"sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272",
|
||||
"sha256:e3699852e22aa68c10de06524a3721ade969abf382da95884e6a10ff798f9281",
|
||||
"sha256:e847774f8ffd5b398a75bc1c18fbb56564cda3d629fe68fd81971fece2d3c67e",
|
||||
"sha256:ffb7a888a047696e7f8240d649b43fb3644f14f0ee229077e7f6b9f9081635bd"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.9.3"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb",
|
||||
"sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.8'",
|
||||
"version": "==3.0.9"
|
||||
},
|
||||
"python-dotenv": {
|
||||
"hashes": [
|
||||
"sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f",
|
||||
"sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.20.0"
|
||||
},
|
||||
"setuptools": {
|
||||
"hashes": [
|
||||
"sha256:7a2e7e95c3bf33f356b4c59aee7a6848585c4219dd3e941e43cc117888f210e4",
|
||||
"sha256:c04a012ae3a1b2cc2aeed4893377b70ea61c6c143d0acceea16ec4b60de6e40d"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==65.0.1"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
"hashes": [
|
||||
"sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae",
|
||||
|
@ -39,5 +227,38 @@
|
|||
"version": "==0.4.2"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
"develop": {
|
||||
"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"
|
||||
},
|
||||
"django-debug-toolbar": {
|
||||
"hashes": [
|
||||
"sha256:89a52128309eb4da12738801ff0c202d2ff8730d1c3225fac6acf630c303e661",
|
||||
"sha256:97965f2630692de316ea0c1ca5bfa81660d7ba13146dbc6be2059cf55b35d0e5"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.5.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
"hashes": [
|
||||
"sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae",
|
||||
"sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.4.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ If you're new to Django, see [Getting Started with Django](https://www.djangopro
|
|||
* Initialize the application:
|
||||
|
||||
```shell
|
||||
cd src
|
||||
docker-compose build
|
||||
```
|
||||
* Run the server: `docker-compose up`
|
||||
|
@ -18,4 +19,4 @@ If you're new to Django, see [Getting Started with Django](https://www.djangopro
|
|||
### 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)
|
||||
1. Run `cd src`, `docker-compose up`, and `docker-compose exec app pipenv update` to perform the upgrade and generate a new [Pipfile.lock](./src/Pipfile.lock)
|
|
@ -2,8 +2,10 @@ version: "3.0"
|
|||
services:
|
||||
app:
|
||||
build: .
|
||||
depends_on:
|
||||
- db
|
||||
volumes:
|
||||
- ./app:/app
|
||||
- .:/app
|
||||
links:
|
||||
- db
|
||||
working_dir: /app
|
||||
|
@ -13,19 +15,22 @@ services:
|
|||
condition: on-failure
|
||||
max_attempts: 5
|
||||
environment:
|
||||
# Ensure stdout and stderr are sent straight to the terminal without buffering
|
||||
# Send stdout and stderr 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
|
||||
# Tell Django where to find its configuration
|
||||
- DJANGO_SETTINGS_MODULE=registrar.config.settings
|
||||
# Set a local key for Django
|
||||
- DJANGO_SECRET_KEY=feedabee
|
||||
# Run Django in debug mode on local
|
||||
- DJANGO_DEBUG=True
|
||||
stdin_open: true
|
||||
tty: true
|
||||
ports:
|
||||
- "8000:8000"
|
||||
command: "python"
|
||||
- "8080:8000"
|
||||
# command: "python"
|
||||
command: "python manage.py runserver 0.0.0.0:8000"
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
|
|
@ -11,7 +11,7 @@ container are also owned by the same user on the host system.
|
|||
import sys
|
||||
import os
|
||||
import pwd
|
||||
import subprocess # nosec
|
||||
import subprocess
|
||||
|
||||
HOST_UID = os.stat("/app").st_uid
|
||||
HOST_USER = "james"
|
||||
|
@ -41,7 +41,7 @@ if __name__ == "__main__":
|
|||
username += "0"
|
||||
home_dir = "/home/%s" % username
|
||||
subprocess.check_call(
|
||||
[ # nosec
|
||||
[
|
||||
"useradd",
|
||||
"-d",
|
||||
home_dir,
|
||||
|
@ -53,4 +53,4 @@ if __name__ == "__main__":
|
|||
)
|
||||
os.environ["HOME"] = "/home/%s" % pwd.getpwuid(HOST_UID).pw_name
|
||||
os.setuid(HOST_UID)
|
||||
os.execvp(sys.argv[1], sys.argv[1:]) # nosec
|
||||
os.execvp(sys.argv[1], sys.argv[1:])
|
21
src/manage.py
Executable file
21
src/manage.py
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
src/registrar/__init__.py
Normal file
0
src/registrar/__init__.py
Normal file
0
src/registrar/config/__init__.py
Normal file
0
src/registrar/config/__init__.py
Normal file
203
src/registrar/config/settings.py
Normal file
203
src/registrar/config/settings.py
Normal file
|
@ -0,0 +1,203 @@
|
|||
"""
|
||||
Django settings for .gov registrar project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 4.0.6.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.0/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.0/ref/settings/
|
||||
|
||||
IF you'd like to see all of these settings in the running app:
|
||||
|
||||
```shell
|
||||
$ docker-compose exec app python manage.py shell
|
||||
>>> from django.conf import settings
|
||||
>>> dir(settings)
|
||||
```
|
||||
|
||||
"""
|
||||
import environs
|
||||
import os
|
||||
from cfenv import AppEnv
|
||||
from pathlib import Path
|
||||
|
||||
env = environs.Env()
|
||||
|
||||
# Get secrets from Cloud.gov user provided service, if exists
|
||||
# If not, get secrets from environment variables
|
||||
key_service = AppEnv().get_service(name="getgov-credentials")
|
||||
if key_service and key_service.credentials:
|
||||
secret = key_service.credentials.get
|
||||
else:
|
||||
secret = env
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = secret("DJANGO_SECRET_KEY")
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = env.bool("DJANGO_DEBUG", default=False)
|
||||
|
||||
# TODO: configure and document security settings
|
||||
ALLOWED_HOSTS = [
|
||||
'getgov-unstable.app.cloud.gov',
|
||||
'get.gov'
|
||||
]
|
||||
ALLOWED_CIDR_NETS = ['10.0.0.0/8'] # nosec
|
||||
USE_X_FORWARDED_HOST = True
|
||||
SESSION_COOKIE_SECURE = True
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_HTTPONLY = True
|
||||
CORS_ALLOW_ALL_ORIGINS = False
|
||||
|
||||
|
||||
# TODO: are all of these needed? Need others?
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
]
|
||||
|
||||
# TODO: document these for future maintainers
|
||||
MIDDLEWARE = [
|
||||
'allow_cidr.middleware.AllowCIDRMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'csp.middleware.CSPMiddleware',
|
||||
]
|
||||
|
||||
# TODO: decide on template engine and document in ADR
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [BASE_DIR / 'templates'],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
# No file logger is configured, because containerized apps
|
||||
# do not log to the file system.
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"verbose": {
|
||||
"format": "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] "
|
||||
"%(message)s",
|
||||
"datefmt": "%d/%b/%Y %H:%M:%S",
|
||||
},
|
||||
"simple": {
|
||||
"format": "%(levelname)s %(message)s",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"level": "DEBUG" if DEBUG else "INFO",
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "verbose",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"django": {
|
||||
"handlers": ["console"],
|
||||
"propagate": True,
|
||||
"level": os.getenv("DJANGO_LOG_LEVEL", "DEBUG"),
|
||||
},
|
||||
"django.template": {
|
||||
"handlers": ["console"],
|
||||
"propagate": True,
|
||||
"level": "INFO",
|
||||
},
|
||||
"registrar": {
|
||||
"handlers": ["console"],
|
||||
"propagate": True,
|
||||
"level": "INFO",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': env.dj_db_url('DATABASE_URL'),
|
||||
}
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.0/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
TIME_ZONE = 'UTC'
|
||||
USE_I18N = True
|
||||
USE_TZ = True
|
||||
USE_L10N = True
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.0/howto/static-files/
|
||||
|
||||
STATIC_ROOT = BASE_DIR / 'static'
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
ADMIN_URL = 'admin/'
|
||||
|
||||
ROOT_URLCONF = 'registrar.config.urls'
|
||||
WSGI_APPLICATION = 'registrar.config.wsgi.application'
|
||||
|
||||
# TODO: FAC example for REST framework
|
||||
API_VERSION = "0"
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": [
|
||||
"rest_framework.authentication.BasicAuthentication",
|
||||
"users.auth.ExpiringTokenAuthentication",
|
||||
],
|
||||
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
|
||||
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
|
||||
"PAGE_SIZE": 10,
|
||||
"TEST_REQUEST_RENDERER_CLASSES": [
|
||||
"rest_framework.renderers.MultiPartRenderer",
|
||||
"rest_framework.renderers.JSONRenderer",
|
||||
"rest_framework.renderers.TemplateHTMLRenderer",
|
||||
"rest_framework.renderers.BrowsableAPIRenderer",
|
||||
],
|
||||
"TEST_REQUEST_DEFAULT_FORMAT": "api",
|
||||
}
|
||||
|
||||
# TODO: FAC example for login.gov
|
||||
SIMPLE_JWT = {
|
||||
'ALGORITHM': 'RS256',
|
||||
'AUDIENCE': None,
|
||||
'ISSUER': 'https://idp.int.identitysandbox.gov/',
|
||||
'JWK_URL': 'https://idp.int.identitysandbox.gov/api/openid_connect/certs',
|
||||
'LEEWAY': 0,
|
||||
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.UntypedToken',),
|
||||
'USER_ID_CLAIM': 'sub',
|
||||
}
|
||||
TOKEN_AUTH = {"TOKEN_TTL": 3600}
|
||||
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
23
src/registrar/config/urls.py
Normal file
23
src/registrar/config/urls.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
"""URL Configuration
|
||||
|
||||
For more information see:
|
||||
https://docs.djangoproject.com/en/4.0/topics/http/urls/
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
|
||||
from registrar.views import health
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path("health/", health.health)
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
import debug_toolbar
|
||||
|
||||
urlpatterns = [
|
||||
path("__debug__/", include(debug_toolbar.urls)),
|
||||
] + urlpatterns
|
14
src/registrar/config/wsgi.py
Normal file
14
src/registrar/config/wsgi.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
"""
|
||||
WSGI config.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
application = get_wsgi_application()
|
0
src/registrar/views/__init__.py
Normal file
0
src/registrar/views/__init__.py
Normal file
4
src/registrar/views/health.py
Normal file
4
src/registrar/views/health.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from django.http import HttpResponse
|
||||
|
||||
def health(request):
|
||||
return HttpResponse("OK")
|
1
src/runtime.txt
Normal file
1
src/runtime.txt
Normal file
|
@ -0,0 +1 @@
|
|||
3.10.x
|
Loading…
Add table
Add a link
Reference in a new issue