Skip to content

Commit 103eea2

Browse files
committed
Hubert Gabryel
1 parent 53b6c94 commit 103eea2

26 files changed

+1787
-0
lines changed

.gitignore

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*.pyo
5+
*.pyd
6+
*.so
7+
*.egg-info/
8+
.eggs/
9+
10+
# Virtualenv
11+
.venv/
12+
venv/
13+
ENV/
14+
15+
# Pytest
16+
.pytest_cache/
17+
18+
# Coverage
19+
.coverage
20+
.coverage.*
21+
htmlcov/
22+
23+
# Logs
24+
*.log
25+
26+
# OS
27+
.DS_Store
28+
29+
# Editor
30+
.vscode/
31+
.idea/
32+
33+
# Terraform
34+
.terraform/
35+
*.tfstate
36+
*.tfstate.*
37+
.terraform.lock.hcl
38+
39+
# Terraform crash logs
40+
crash.log
41+
crash.*.log
42+
43+
# Docker
44+
*.pid
45+
46+
# Local env files
47+
.env
48+
.env.*
49+
50+
# Scripts tmp
51+
/tmp/

API.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# API and CLI Guide
2+
3+
## Run with Docker Compose
4+
5+
```bash
6+
cp .env.example .env
7+
# edit .env and set POSTGRES_PASSWORD
8+
docker compose up --build
9+
```
10+
11+
API will be available at `http://localhost:8000`.
12+
The `tests` service runs `pytest` automatically during startup and then exits.
13+
If you want the stack to stop when tests finish, run:
14+
```bash
15+
docker compose up --build --abort-on-container-exit --exit-code-from tests
16+
```
17+
18+
## Run locally
19+
20+
```bash
21+
python -m venv .venv
22+
source .venv/bin/activate
23+
pip install -r requirements.txt
24+
export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/inventory
25+
uvicorn app.main:app --reload
26+
```
27+
28+
## API Spec
29+
30+
### Create server
31+
`POST /servers`
32+
33+
Request:
34+
```json
35+
{"hostname":"srv-1","ip_address":"10.0.0.1","state":"active"}
36+
```
37+
38+
Responses:
39+
- `201` server object
40+
- `400` hostname must be unique or invalid payload
41+
42+
### List servers
43+
`GET /servers`
44+
45+
Responses:
46+
- `200` list of server objects
47+
48+
### Get server
49+
`GET /servers/{id}`
50+
51+
Responses:
52+
- `200` server object
53+
- `404` not found
54+
55+
### Update server
56+
`PUT /servers/{id}`
57+
58+
Request:
59+
```json
60+
{"hostname":"srv-1","ip_address":"10.0.0.2","state":"offline"}
61+
```
62+
63+
Responses:
64+
- `200` server object
65+
- `400` hostname must be unique or invalid payload
66+
- `404` not found
67+
68+
### Delete server
69+
`DELETE /servers/{id}`
70+
71+
Responses:
72+
- `204` deleted
73+
- `404` not found
74+
75+
## CLI Spec
76+
77+
The CLI talks to the API. Set `API_URL` if needed (default `http://localhost:8000`).
78+
79+
```bash
80+
python -m cli list
81+
python -m cli get 1
82+
python -m cli create srv-1 10.0.0.1 active
83+
python -m cli update 1 srv-1b 10.0.0.2 offline
84+
python -m cli delete 1
85+
```
86+
87+
## Tests
88+
89+
Make sure PostgreSQL is running locally, then:
90+
91+
```bash
92+
export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/inventory
93+
pytest
94+
```
95+
96+
Tests skip automatically if PostgreSQL is unavailable.

Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM python:3.11-slim
2+
3+
WORKDIR /app
4+
5+
COPY requirements.txt ./
6+
RUN pip install --no-cache-dir -r requirements.txt
7+
8+
COPY app ./app
9+
COPY tests ./tests
10+
11+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

README.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,155 @@ Validate that:
2929

3030
State is one of: active, offline, retired
3131

32+
# Project Usage
33+
34+
## Run with Docker Compose (default)
35+
36+
```bash
37+
cp .env.example .env
38+
# edit .env and set POSTGRES_PASSWORD
39+
docker compose up --build
40+
```
41+
42+
This starts `api` and `db`. The `tests` service runs once with verbose output and exits; it does not stop the stack. If you want the stack to stop right after tests, run:
43+
44+
```bash
45+
docker compose up --build --abort-on-container-exit --exit-code-from tests
46+
```
47+
48+
API is available at `http://localhost:8000`.
49+
50+
## CLI
51+
52+
```bash
53+
python -m cli list
54+
python -m cli get 1
55+
python -m cli create srv-1 10.0.0.1 active
56+
python -m cli update 1 srv-1b 10.0.0.2 offline
57+
python -m cli delete 1
58+
```
59+
60+
# Tests
61+
62+
Tests run automatically during `docker compose up --build`. You can also run them locally:
63+
64+
```bash
65+
export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/inventory
66+
pytest
67+
```
68+
69+
Note: during tests you may see a PostgreSQL "duplicate key value violates unique constraint" log entry.
70+
This is expected and comes from the unique-hostname validation test.
71+
72+
# Security, Lint, and Dependency Checks
73+
74+
All tools below are free/open-source. Run them locally:
75+
76+
```bash
77+
./scripts/security_checks.sh
78+
```
79+
80+
What it checks:
81+
- Python linting with `ruff`
82+
- Static security analysis with `bandit`
83+
- Dependency vulnerability scan with `pip-audit`
84+
- Dockerfile linting with `hadolint` (via container)
85+
- Repo vulnerability scan with `trivy` (via container)
86+
87+
To see outdated dependencies:
88+
89+
```bash
90+
./scripts/check_updates.sh
91+
```
92+
93+
# Optional AWS Deploy Switch
94+
95+
Default deployment is local Docker Compose. For AWS, use the deploy switch:
96+
97+
```bash
98+
DEPLOY_TARGET=aws \\
99+
AWS_REGION=us-east-1 \\
100+
AWS_ACCOUNT_ID=123456789012 \\
101+
ECR_REPO=inventory-api \\
102+
ECS_CLUSTER=your-cluster \\
103+
ECS_SERVICE=your-service \\
104+
DATABASE_URL=postgresql://user:pass@your-rds:5432/inventory \\
105+
EXECUTION_ROLE_ARN=arn:aws:iam::123456789012:role/ecsTaskExecutionRole \\
106+
TASK_ROLE_ARN=arn:aws:iam::123456789012:role/ecsTaskRole \\
107+
./scripts/deploy.sh
108+
```
109+
110+
Notes:
111+
- Requires AWS CLI, Docker, and an existing ECS cluster/service.
112+
- Task definition template lives in `deploy/aws/task-def.json`.
113+
- The script builds and pushes the image to ECR, then updates the ECS service.
114+
- This path expects an explicit `DATABASE_URL` (no Secrets Manager integration). Use the Terraform path if you want Secrets Manager + full infra provisioning.
115+
116+
# AWS Terraform Deployment (provision everything)
117+
118+
This path provisions the VPC, subnets, ALB, ECS Fargate, ECR repo, and RDS PostgreSQL via Terraform.
119+
You only provide AWS credentials and a DB password.
120+
121+
Minimal (uses defaults):
122+
123+
```bash
124+
./scripts/deploy_terraform_aws.sh
125+
```
126+
127+
Optional overrides:
128+
129+
```bash
130+
export AWS_REGION=us-east-1
131+
export PROJECT_NAME=inventory
132+
export DB_USERNAME=inventory
133+
# Optional: pin Postgres engine version (otherwise latest available in region)
134+
export DB_ENGINE_VERSION=18.1
135+
# Optional HTTPS (requires domain + ACM certificate)
136+
export ACM_CERT_ARN=arn:aws:acm:us-east-1:123456789012:certificate/your-cert-id
137+
# Optional: attach a domain and create Route53 record automatically
138+
export API_DOMAIN_NAME=api.example.com
139+
export ROUTE53_ZONE_ID=Z1234567890
140+
./scripts/deploy_terraform_aws.sh
141+
```
142+
143+
After deploy, run a smoke test:
144+
145+
```bash
146+
export API_URL=http://<alb-dns-name>
147+
./scripts/aws_smoke_test.sh
148+
```
149+
150+
Outputs are available in `deploy/aws/terraform/outputs.tf`.
151+
152+
Notes:
153+
- This Terraform stack uses private subnets for ECS/RDS, NAT for egress, and a public ALB.
154+
- If you do not provide `ACM_CERT_ARN`, the ALB runs HTTP only. When you have a domain, add ACM to enable HTTPS.
155+
- Destroy with: `cd deploy/aws/terraform && terraform destroy`.
156+
- The RDS password is generated randomly and stored in AWS Secrets Manager.
157+
- ECS pulls `DATABASE_URL` directly from Secrets Manager at runtime.
158+
- Terraform state will contain the generated secret value; store state securely (e.g., S3 + KMS).
159+
- SSL/TLS requires a valid ACM certificate for your domain. For the automatic smoke test over HTTPS, set `API_DOMAIN_NAME` + `ROUTE53_ZONE_ID` so the script can hit a matching cert.
160+
- RDS deletion protection and performance insights are enabled for security; disable them before `terraform destroy` if needed (cost impact).
161+
162+
# Terraform Security Checks
163+
164+
Run Terraform linting + security scans:
165+
166+
```bash
167+
./scripts/terraform_security_checks.sh
168+
```
169+
170+
This runs:
171+
- `terraform fmt -check` and `terraform validate`
172+
- `tfsec` and `checkov` via Docker for security posture checks
173+
174+
Notes:
175+
- Some tfsec checks are intentionally suppressed for the public ALB and optional HTTP-only mode when ACM is not provided.
176+
177+
# Terraform Provider Version Check
178+
179+
To check for provider updates and refresh the lockfile:
180+
181+
```bash
182+
./scripts/terraform_update_check.sh
183+
```

app/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)