ScotterMonk / scottswain

This project is in support of efforts to hire python engineers.
MIT License
0 stars 0 forks source link

project-python-flask

This project is in support of efforts to hire python engineers.

Getting Started

Ensure you can run the application locally by cloning it.

These directions assume you will use poetry for dependency and environment management.

Install dependencies

poetry install

Set up your secrets

Create environment file

Create a file named .env in your project root. Contents:

SECRET_KEY=mysecret
DATABASE_URI=sqlite:///users.db
TEST_DATABASE_URI=sqlite:///:memory:
FLASK_ENV=development

Note: Changes to the values in this file will be cached, so be sure to restart the application to get new values.

Modify config.py

This file resides in the /project root/app folder. Notice the following function accepts two arguments:

os.getenv(key, default value)

Depending on how secure you want your application to be, you may wish to modify the second argument to be less revealing, like so:

SECRET_KEY = os.getenv("SECRET_KEY", "mysecret")
# would change to:
SECRET_KEY = os.getenv("SECRET_KEY", "notmysecret")

Make sure your .env file is not uploaded to GitHub

Find the .gitignore file. It is one folder "up" from your project root folder. In that file, look for the # Environments section. It should have at least the exclusions you see here:

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

Building the software

Linting

You many need to install the pre-commit project

Then run

pre-commit run --all-files

You should get output showing "Passed" or (for json files) "Skipped"

trim trailing whitespace.................................................Passed
fix end of files.........................................................Passed
check yaml...............................................................Passed
check json...........................................(no files to check)Skipped
black....................................................................Passed

Automated tests

There are a couple of automated tests to run.

poetry run pytest --verbose

You should see something similar to:

============================================================================================= test session starts ==============================================================================================
platform darwin -- Python 3.12.6, pytest-8.3.3, pluggy-1.5.0 -- /Users/boyd.hemphill/Library/Caches/pypoetry/virtualenvs/project-python-flask-mx59eYov-py3.12/bin/python
cachedir: .pytest_cache
rootdir: /Users/boyd.hemphill/code/project-python-flask
configfile: pyproject.toml
testpaths: tests
collected 3 items

tests/test_auth.py::test_register_user PASSED                                                                                                                                                            [ 33%]
tests/test_auth.py::test_login_user PASSED                                                                                                                                                               [ 66%]
tests/test_auth.py::test_login_invalid_user PASSED                                                                                                                                                       [100%]

============================================================================================== 3 passed in 0.03s ===============================================================================================

Database Management & Install Tips

Some tips on managing the SQLite database in the beginning and any time the database structure is changed in the models.py file.

Initialization

To initialize the SQLite database, you'll need to use Flask-Migrate:

After following these steps, your SQLite database should be initialized and ready to use. The tables defined in your models.py file will be created in the database.

Upkeep

Whenever you make changes to your models, you'll need to create a new migration and apply it:

flask db migrate -m "Description of changes"
flask db upgrade

Once you update models.py file with any schema changes:

Starting the application

export FLASK_ENV=development # use the development settings
poetry run python app.py

You should see something like this:

/code/project-python-flask >poetry run python run.py
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 413-423-614

Exercising the API

Create a user that will allow you to authenticate. For ease of using the project you submit, please do not change the credentials.

curl \
  -X POST http://127.0.0.1:5000/register \
  -H "Content-Type: application/json" \
  -d '{"username":"Dev Userson", "email":"dev.userson@example.com", "password":"sosecure"}'

Show that the user can log in:

curl -X POST http://127.0.0.1:5000/login \
-H "Content-Type: application/json" \
-d '{"email":"dev.userson@example.com", "password":"sosecure"}'

Users in database (some have roles assigned, some don't)

See API call below titled "SHOW ALL USERS with ALL ROLES"

API calls

# REGISTER
curl -X POST http://127.0.0.1:5000/register \
     -H "Content-Type: application/json" \
     -d '{"username":"Dev Userson", "email":"dev.userson@example.com", "password":"sosecure"}'

# LOGIN
curl -X POST http://127.0.0.1:5000/login \
     -H "Content-Type: application/json" \
     -d '{"email":"dev.userson@example.com", "password":"sosecure"}'

# TOGGLE ACTIVE
curl -X POST http://127.0.0.1:5000/toggle-active \
     -H "Content-Type: application/json" \
     -d '{"email":"dev.userson@example.com"}'

# SHOW USER PROFILE
curl -X POST http://127.0.0.1:5000/profile \
     -H "Content-Type: application/json" \
     -d '{"username":"Scott Swain", "email":""}'

# SHOW ALL USERS (deprecated)
curl -X GET http://127.0.0.1:5000/users \
     -H "Content-Type: application/json"

# SHOW ALL USERS with ALL ROLES
curl -X GET http://127.0.0.1:5000/users-roles \
     -H "Content-Type: application/json"

# ACCESS REPORT
# (Note: can replace "all_users" below with "active_users" or "inactive_users")
curl -X POST http://127.0.0.1:5000/access-report \
     -H "Content-Type: application/json" \
     -d '{"limit_to":"all_users"}'

# DELETE USER
curl -X POST http://127.0.0.1:5000/delete-user \
     -H "Content-Type: application/json" \
     -d '{"email":"dev.userson@example.com"}'

# SHOW ALL ROLE(S)
curl -X GET http://127.0.0.1:5000/roles-show \
     -H "Content-Type: application/json"

# CREATE ROLE(S)
curl -X POST http://127.0.0.1:5000/create-roles \
     -H "Content-Type: application/json" \
     -d '{"roles_depts":["Senior Dev,Getting Started", "Dev,Getting Started"]}'

# ASSIGN ROLE(S)
# (Note: any number of users can be assigned any number of role/dept combinations.)
curl -X POST http://127.0.0.1:5000/assign-roles \
     -H "Content-Type: application/json" \
     -d '{"emails_roles_depts":["dev.userson@example.com,Senior Dev,Getting Started", "scott@oceanmedia.net,Dev,Getting Started", "scott@oceanmedia.net,Dev,Finance Dept"]}'

Tasks

For each task please follow this process:

  1. Create an issue in your Github project, you are welcome to copy the text of the task provided or write your own, but please use the title here as the title of your GH issue.
  2. Add at least one test to your code showing your solution works and ensuring it will continue to work as expected.
  3. Make a PR to your code.
  4. Merge your PR when you are happy.

:information_source: - All input and response should be assumed to be via curl. There is no expectation of a front end being created for this project.

:warning: - Please manage your time. We expect between three and four hours of effort and the associated quality. If you would like to take more time you are welcome to do so, but it is in no way required.

Most importantly, have fun. Show off a bit. Push an opinion or two forward to spark a discussion.

Required

The following are "required." We recommend working these first and expect they will take between 2 and 3 hours to complete. If you do not have time to complete them all that is fine. Ensure you have a priority list and are able to discuss why you prioritized them as you did.

Github Action

Create a Github action that runs the linting and automated tests. It is a Victory goal that humans don't look at code that is not linted to standard and passing tests unless there is a specfic reason (e.g. a draft pull request).

Active users

As an application administrator I want to be able to mark a user as "inactive" so that they cannot log in or perform any actions on the system.

Acceptance Criteria

Access Report

As a compliance officer I want to be able to check a report that tells me who my users are and what their access level is so that I can conduct the monthly reviews and drive remediation as required by SOC 2 Type 2.

Accpetance Criteria

Add the role entity to the model

As an application admin I need to assign each user one or more roles so that they have a clear and predictable set of permissions. I do not need to override roles at this time.

Acceptance Criteria

Fix our secrets in code issue

As a compliance officer I want our credentials and other sensitive information removed from source control and stored according to OWASP best practices so that our operations are hardened against external and internal attacks.

In config.py there are secrets stored in plain text.

  1. Write a Github issue in your project describing the problem in a way you'd like to get it from a product manager/owner.
  2. Implement your solution and make a PR.

Implement the profile route

:information_source: - See app/routes/user_routes.py

Write a detailed Github issue explaining your understanding of the requirements as you infer them. Write them as if you will not be the one to work on the task.

Optional Tasks

If you have some extra time and would like to show off a bit, the following are some suggestions to feed your creativity. You are encouraged to come up with, document and solve your own problem. Victory places a high value on engineers who work to ensure team efficiency.

Think outside the box for all of this. For example maybe instead of fixing something you'd rather write out a list of several tickets and prioritize them. In this case we will discuss what you are suggesting, approaches and the like.

Alternatively you could find one thing that shows off a particular passion and dive as deep as you like.

Or, you could come up approach we have not thought of. Think of this as a way to shape your interiew towards your interests and passion.

:information_source: - If you decide to tackle something and run out of time, simply make a PR but don't merge it. Note this in your email telling us where to find your project and it becomes a conversation piece for the final interview.

Find and fix a security issue

There are many issues of security with our application. You've seen above how we like to communicate tasks, so:

Improve the build

Our build does some linting with pre-commit and runs our tests. If this is a project you are responsible for what would you add?

Remember that writing the ticket is 60% of what we are looking for here. Only implement if this is something you are passionate about.

Move us to Postgresql

SQLlite is great for something like an interview project. Most Victory projects are backed by Postgres or MySQL.

Show off your use of a debugger and its integration with your IDE

Show us the lack of print statements in your code and how you go about tracking down values of variables and the like when looking for defects in the code.

Evaluation Criteria

The people evaluating your submission will do the following before we schedule the final interview.

On a global level, we are evaluating you on your ability

We will do the following:

  1. Clone and run your fork following the instructions in the README under "Getting Started". We are simply checking to ensure the application functions as expected.
    • We expect there to be instructions for testing the creation of roles and assigning users for us to use. (remember that we prize solid communication)
  2. Read each PR
    • Be sure you have a good commit message that describes why the work is done like it is (not what was done, we can see that in the code)
      • this is a chance to show off written communication skills
    • Be sure your code has passed all checks in the build
  3. Attempt to run each PR to show that the code is in the expected functional state
  4. Attempt to run the test suite
  5. Read each Github issue you created and note if/how you tracked your progress.

Next Step - In Person Technical

Within five business days we will respond to you to schedule a 90 minute in-person interview with Victory staff or a note to let you know we are going in a different direction.

To prepare for the interview be ready to

Please note that folks on the team are often taking a position counter to your own. It is of primary importance that members of Victory teams can disagree, discuss and come to a common understanding and path forward.

You should walk away with a solid understanding of what it is like to work on a Victory team on a daily basis. We understand that you may not want to work the way we do. Better for all concerned if we figure that out as early as possible.

Thank you

We are going to make six figure bet on you. You are going to put your career in our hands and expect us to help you grow professionally.

We deeply appreciate the time you are taking to ensure joining Victory is of benefit to all concerned (yourself, Victory and our clients).