Skip to content

Commit

Permalink
Merge pull request #5 from cisagov/first-commits
Browse files Browse the repository at this point in the history
Boosh!
  • Loading branch information
felddy authored Oct 21, 2024
2 parents acf9fc2 + 74a9505 commit 3faa585
Show file tree
Hide file tree
Showing 50 changed files with 3,209 additions and 313 deletions.
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# https://coverage.readthedocs.io/en/latest/config.html

[run]
source = src/example
source = src/cyhy_db
omit =
branch = true

Expand Down
8 changes: 4 additions & 4 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ updates:
- dependency-name: hashicorp/setup-terraform
- dependency-name: mxschmitt/action-tmate
- dependency-name: step-security/harden-runner
# # Managed by cisagov/cyhy-db
# - dependency-name: actions/download-artifact
# - dependency-name: actions/upload-artifact
# - dependency-name: github/codeql-action
# Managed by cisagov/skeleton-python-library
- dependency-name: actions/download-artifact
- dependency-name: actions/upload-artifact
- dependency-name: github/codeql-action
package-ecosystem: github-actions
schedule:
interval: weekly
Expand Down
12 changes: 0 additions & 12 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,6 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
steps:
Expand Down Expand Up @@ -286,10 +282,6 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
steps:
Expand Down Expand Up @@ -341,10 +333,6 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
steps:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
## Python ##
__pycache__
.coverage
.hypothesis
.mypy_cache
.pytest_cache
.python-version
*.egg-info
dist

## VSCode ##
.vscode
112 changes: 98 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,104 @@
[![Coverage Status](https://coveralls.io/repos/github/cisagov/cyhy-db/badge.svg?branch=develop)](https://coveralls.io/github/cisagov/cyhy-db?branch=develop)
[![Known Vulnerabilities](https://snyk.io/test/github/cisagov/cyhy-db/develop/badge.svg)](https://snyk.io/test/github/cisagov/cyhy-db)

This is a generic skeleton project that can be used to quickly get a
new [cisagov](https://github.com/cisagov) Python library GitHub
project started. This skeleton project contains [licensing
information](LICENSE), as well as
[pre-commit hooks](https://pre-commit.com) and
[GitHub Actions](https://github.com/features/actions) configurations
appropriate for a Python library project.

## New Repositories from a Skeleton ##

Please see our [Project Setup guide](https://github.com/cisagov/development-guide/tree/develop/project_setup)
for step-by-step instructions on how to start a new repository from
a skeleton. This will save you time and effort when configuring a
new repository!
This repository implements a Python module for interacting with a Cyber Hygiene database.

## Pre-requisites ##

- [Python 3.11](https://www.python.org/downloads/) or newer
- A running [MongoDB](https://www.mongodb.com/) instance that you have access to

## Starting a Local MongoDB Instance for Testing ##

> [!IMPORTANT]
> This requires [Docker](https://www.docker.com/) to be installed in
> order for this to work.
You can start a local MongoDB instance in a container with the following
command:

```console
pytest -vs --mongo-express
```

> [!NOTE]
> The command `pytest -vs --mongo-express` not only starts a local
> MongoDB instance, but also runs all the `cyhy-db` unit tests, which will
> create various collections and documents in the database.
Sample output (trimmed to highlight the important parts):

```console
<snip>
MongoDB is accessible at mongodb://mongoadmin:secret@localhost:32859 with database named "test"
Mongo Express is accessible at http://admin:pass@localhost:8081

Press Enter to stop Mongo Express and MongoDB containers...
```

Based on the example output above, you can access the MongoDB instance at
`mongodb://mongoadmin:secret@localhost:32859` and the Mongo Express web
interface at `http://admin:pass@localhost:8081`. Note that the MongoDB
containers will remain running until you press "Enter" in that terminal.

## Example Usage ##

Once you have a MongoDB instance running, the sample Python code below
demonstrates how to initialize the database, create a new request document, save
it, and then retrieve it.

```python
import asyncio
from cyhy_db import initialize_db
from cyhy_db.models import RequestDoc
from cyhy_db.models.request_doc import Agency

async def main():
# Initialize the CyHy database
await initialize_db("mongodb://mongoadmin:secret@localhost:32859", "test")

# Create a new CyHy request document and save it in the database
new_request = RequestDoc(
agency=Agency(name="Acme Industries", acronym="AI")
)
await new_request.save()

# Find the request document and print its agency information
request = await RequestDoc.get("AI")
print(request.agency)

asyncio.run(main())
```

Output:

```console
name='Acme Industries' acronym='AI' type=None contacts=[] location=None
```

## Additional Testing Options ##

> [!WARNING]
> The default usernames and passwords are for testing purposes only.
> Do not use them in production environments. Always set strong, unique
> credentials.
### Environment Variables ###

| Variable | Description | Default |
|----------|-------------|---------|
| `MONGO_INITDB_ROOT_USERNAME` | The MongoDB root username | `mongoadmin` |
| `MONGO_INITDB_ROOT_PASSWORD` | The MongoDB root password | `secret` |
| `DATABASE_NAME` | The name of the database to use for testing | `test` |
| `MONGO_EXPRESS_PORT` | The port to use for the Mongo Express web interface | `8081` |

### Pytest Options ###

| Option | Description | Default |
|--------|-------------|---------|
| `--mongo-express` | Start a local MongoDB instance and Mongo Express web interface | n/a |
| `--mongo-image-tag` | The tag of the MongoDB Docker image to use | `docker.io/mongo:latest` |
| `--runslow` | Run slow tests | n/a |

## Contributing ##

Expand Down
2 changes: 1 addition & 1 deletion bump_version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -o nounset
set -o errexit
set -o pipefail

VERSION_FILE=src/example/_version.py
VERSION_FILE=src/cyhy_db/_version.py

HELP_INFORMATION="bump_version.sh (show|major|minor|patch|prerelease|build|finalize)"

Expand Down
4 changes: 3 additions & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
[pytest]
addopts = -v -ra --cov
addopts = -v -ra --cov --log-cli-level=INFO
asyncio_default_fixture_loop_scope = session
asyncio_mode = auto
2 changes: 1 addition & 1 deletion setup-env
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ for req_file in "requirements-dev.txt" "requirements-test.txt" "requirements.txt
done

# Install all necessary mypy type stubs
mypy --install-types src/
mypy --install-types --non-interactive src/

# Install git pre-commit hooks now or later.
pre-commit install ${INSTALL_HOOKS:+"--install-hooks"}
Expand Down
39 changes: 19 additions & 20 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ def get_version(version_file):


setup(
name="example",
name="cyhy-db",
# Versions should comply with PEP440
version=get_version("src/example/_version.py"),
description="Example Python library",
version=get_version("src/cyhy_db/_version.py"),
description="CyHy Database Python library",
long_description=readme(),
long_description_content_type="text/markdown",
# Landing page for CISA's cybersecurity mission
Expand Down Expand Up @@ -75,38 +75,37 @@ def get_version(version_file):
# that you indicate whether you support Python 2, Python 3 or both.
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
],
python_requires=">=3.7",
python_requires=">=3.11",
# What does your project relate to?
keywords="skeleton",
keywords=["cyhy", "database"],
packages=find_packages(where="src"),
package_dir={"": "src"},
package_data={"example": ["data/*.txt"]},
package_data={"cyhy_db": ["py.typed"]},
py_modules=[splitext(basename(path))[0] for path in glob("src/*.py")],
include_package_data=True,
install_requires=["docopt", "schema", "setuptools >= 24.2.0"],
install_requires=[
"beanie",
"pydantic[email, hypothesis]", # hypothesis plugin is currently disabled: https://github.com/pydantic/pydantic/issues/4682
"setuptools",
],
extras_require={
"test": [
"pytest-asyncio",
"coverage",
# coveralls 1.11.0 added a service number for calls from
# GitHub Actions. This caused a regression which resulted in a 422
# response from the coveralls API with the message:
# Unprocessable Entity for url: https://coveralls.io/api/v1/jobs
# 1.11.1 fixed this issue, but to ensure expected behavior we'll pin
# to never grab the regression version.
"coveralls != 1.11.0",
"coveralls",
"docker",
"hypothesis",
"mimesis-factory",
"mimesis",
"pre-commit",
"pytest-cov",
"pytest-factoryboy",
"pytest",
]
},
# Conveniently allows one to run the CLI tool as `example`
entry_points={"console_scripts": ["example = example.example:main"]},
entry_points={},
)
7 changes: 4 additions & 3 deletions src/example/__init__.py → src/cyhy_db/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""The example library."""
"""The cyhy_db package provides an interface to a CyHy database."""

# We disable a Flake8 check for "Module imported but unused (F401)" here because
# although this import is not directly used, it populates the value
# package_name.__version__, which is used to get version information about this
# Python package.

from ._version import __version__ # noqa: F401
from .example import example_div
from .db import initialize_db

__all__ = ["example_div"]
__all__ = ["initialize_db"]
1 change: 1 addition & 0 deletions src/cyhy_db/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "1.0.0"
54 changes: 54 additions & 0 deletions src/cyhy_db/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""CyHy database top-level functions."""

# Third-Party Libraries
from beanie import Document, View, init_beanie
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase

from .models import (
CVEDoc,
HostDoc,
HostScanDoc,
KEVDoc,
NotificationDoc,
PlaceDoc,
PortScanDoc,
ReportDoc,
RequestDoc,
SnapshotDoc,
SystemControlDoc,
TallyDoc,
TicketDoc,
VulnScanDoc,
)

ALL_MODELS: list[type[Document] | type[View] | str] = [
CVEDoc,
HostDoc,
HostScanDoc,
KEVDoc,
NotificationDoc,
PlaceDoc,
PortScanDoc,
RequestDoc,
ReportDoc,
SnapshotDoc,
SystemControlDoc,
TallyDoc,
TicketDoc,
VulnScanDoc,
]

# Note: ScanDoc is intentionally excluded from the list of models to be imported
# or initialized because it is an abstract base class.


async def initialize_db(db_uri: str, db_name: str) -> AsyncIOMotorDatabase:
"""Initialize the database."""
try:
client: AsyncIOMotorClient = AsyncIOMotorClient(db_uri)
db: AsyncIOMotorDatabase = client[db_name]
await init_beanie(database=db, document_models=ALL_MODELS)
return db
except Exception as e:
print(f"Failed to initialize database with error: {e}")
raise
Loading

0 comments on commit 3faa585

Please sign in to comment.