# Technical documentation — unityAWS

Evidence date: 2026-09-30.

Source: `git@bitbucket.org:overdrive/unityaws.git`, `master` at `e9f10da` (2019-10-08, "zero out response").

The database password is stored in git. This document names the file and does not repeat the secret.

## Repository

| Item | Value |
|---|---|
| Remote | `git@bitbucket.org:overdrive/unityaws.git` |
| Default branch | `master` (`origin/HEAD`) |
| Inspected commit | `e9f10da` |
| Other branches | None |
| Authors | `jaco@overdrive.co.za` (`Jaco Brits` on `37be5a8`, `siliconoverdrive` on the rest) |
| Application language | Python |
| README | Heading `# unityAWS` only |

Clone for this inspection was a full history of the ten commits. The scan-host directory `~/projects/sonar_scan/repos/unityAWS` was not on the machine that produced these notes.

## Layout

```text
README.md
bitbucket-pipelines.yml
config.py
lambda_function.py          # root handler at HEAD
login.py
lambda/lambda_function.py   # second handler, not imported by the root
lambda.zip                  # snapshot from 661f10a, not rebuilt later
pymysql/                    # PyMySQL 0.9.3
PyMySQL-0.9.3.dist-info/
__pycache__/                # cpython-37 bytecode, including config
```

Not in `git ls-files` at `e9f10da`, although the onboarding scan listed them: `sonar-project.properties`, `sonarqube_scan.bat`.

No `requirements.txt`, `serverless.yml`, `template.yaml`, Dockerfile, `.gitignore`, test directory, or SQL file is tracked.

## Runtime and dependencies

| Piece | Evidence |
|---|---|
| Pipeline image | `python:3.5.7` in `bitbucket-pipelines.yml` |
| Bytecode | Filenames `*.cpython-37.pyc` (CPython 3.7) |
| PyMySQL | `PyMySQL-0.9.3.dist-info/METADATA` version 0.9.3, MIT. Classifiers include Python 2.7 and 3.4–3.7 |
| Deploy pipe | `atlassian/aws-lambda-deploy:0.2.1` |
| Lambda runtime setting | Not in git. **Unknown / Requires Confirmation** |

The pipeline does not run `pip install`. The driver that ships is the copy in git.

Standard-library imports in the application files: `json`, `sys`, `logging`. `json` is unused in `login.py`. `sys` is unused in the root `lambda_function.py`.

## Handler contract (root)

File: `lambda_function.py`. Entry: `lambda_handler(event, context)`.

`context` is not read.

### Request

| Field | Where | Required for a normal return |
|---|---|---|
| `body` | `event["body"]`, a JSON string | Yes |
| `action` | Inside that JSON | Yes |
| `username` | `event["username"]` | Only when `action` is `login` |
| `password` | `event["password"]` | Only when `action` is `login` |

`body` is parsed with `json.loads`. A dict already placed in `event["body"]` is not what this code accepts. `loads` expects a string.

### Response when the function returns

| Field | Value |
|---|---|
| `statusCode` | `200` |
| `headers.Access-Control-Allow-Origin` | `*` |
| `body` | `json.dumps(response)` |

`response` is the dict from `login()` when `action` is `login`. Otherwise it is `""`, and the body text is the JSON string `""`.

Login dict:

```json
{"success": "false", "reason": "invalid"}
```

`success` is a string.

### Exceptions the handler does not catch

| Condition | Result |
|---|---|
| No `event["body"]` | Subscript error |
| Body is not JSON text | `json.JSONDecodeError` |
| No `action` | `KeyError` |
| Action `login` without `username` or `password` | `KeyError` |
| Import of `login` cannot connect | `sys.exit()` during import, before the handler |

Lambda's mapping of those failures to an API status is not defined in this repo.

## `login.py`

Module import order:

1. Import `config` and `pymysql`.
2. Bind host, user, password, and database name from config.
3. Set logger to INFO.
4. `pymysql.connect(host, user=name, passwd=password, db=db_name, connect_timeout=5)` inside `try`.
5. On exception, `logger.error("ERROR: Unexpected error: Could not connect to MySql instance.")` and `sys.exit()`.
6. On success, `logger.info("SUCCESS: Connection to RDS mysql instance succeeded")`.

`port = 3306` is unused. PyMySQL 0.9.3 defaults the port to 3306 when it is omitted. The positional first argument is the host, which matches this version's `connect` signature.

`def login(email, password)` does not use `email`, `password`, `conn`, `json`, or a cursor.

## `config.py`

Comment in the file: `config file containing credentials for rds mysql instance`.

| Name | Value in git |
|---|---|
| `db_username` | `dbadmin` |
| `db_password` | Present. Omitted here |
| `db_name` | `unityqa` |
| `db_endpoint` | `unityqa.csigt2kcstpl.us-east-2.rds.amazonaws.com` |

The same four facts are inside `lambda.zip` (`config.py`) and the committed `config.cpython-37.pyc`. Treat the password as exposed. This documentation does not record it.

## Second handler

`lambda/lambda_function.py`:

- Same connect-or-exit block as `login.py`, including its own import of `config`.
- `lambda_handler` returns `{'statusCode': 200, 'body': json.dumps('Lambda , Unity')}`.
- No CORS header.
- Comment `# TODO implement`.
- Not imported by the root module.

If both files are in the deployment zip, which one runs depends on the function's handler property (`lambda_function.lambda_handler` versus `lambda.lambda_function.lambda_handler`). That property is **Unknown / Requires Confirmation**.

## `lambda.zip`

Added in `661f10a` (2019-10-02). `git log` shows no later change. Size on the inspected clone: 120318 bytes.

Entries are `lambda_function.py`, `config.py`, `pymysql/**`, `PyMySQL-0.9.3.dist-info/**`, and `__pycache__/**`. The handler in the zip is the pre-CORS stub that returns `Lambda , Unity`. `login.py` is not in the zip.

The pipeline builds `code.zip` and does not reference `lambda.zip`.

## Deployment

`bitbucket-pipelines.yml`:

```yaml
image: python:3.5.7
pipelines:
  default:
    - step: Build and package
        apt-get update && apt-get install -y zip
        zip -r code.zip *
        artifact: code.zip
    - step: Update Lambda code
        pipe: atlassian/aws-lambda-deploy:0.2.1
        AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
        AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
        AWS_DEFAULT_REGION: us-east-2
        FUNCTION_NAME: qaFunction
        COMMAND: update
        ZIP_FILE: code.zip
```

The YAML uses a normal pipe `variables` block. The sketch above is the effective settings, not a second copy of the file.

Zip path history:

| Commit | Command |
|---|---|
| `437b8c6` | `zip -r code.zip -r /lambda/` |
| `9a9819c` | `zip -r code.zip lambda/` |
| `661f10a` onward | `zip -r code.zip *` |

`*` includes `lambda.zip`, `__pycache__`, and `pymysql`. It does not include `.git`. There is no exclude list.

No VPC, security group, IAM role, environment variable, memory, or timeout is declared. `config.py` is how the function gets the database host, not Lambda environment variables.

## Data

No table, column, or migration is defined in this repository.

The connection selects database `unityqa` and then no statement runs. Schema of that database is **Unknown** from this repo.

Silicon Ark `unityNodejsApi` (inspected revision `8d9588c`, 2019-12-01) documents the same host, database name, and user, and SQL against `users` (`strUsername`, `strPassword`, and other columns). That is a different codebase and a later date. It is not evidence that unityAWS queries those columns.

## Auth

No authorizer, JWT, session, or password comparison is implemented.

The event may carry `username` and `password`. They are passed into `login()` and ignored.

CORS allows origin `*` on the root handler only.

## Logging and monitoring

`logging.getLogger()` at INFO in `login.py` and in `lambda/lambda_function.py`.

Two messages:

- `SUCCESS: Connection to RDS mysql instance succeeded`
- `ERROR: Unexpected error: Could not connect to MySql instance.`

No request log, no metric, and no alarm definition. `print(event['action'])` existed at `9409bbd` and was commented out at `9ddf51c`. It is not active at HEAD.

## Tests and local run

No test file, fixture, or CI test step exists.

A local import of `login` attempts the RDS connection and exits the process on failure. There is no offline path.

## Security notes for reviewers

These are observations from the tree, not a pentest.

- The database password is in `config.py`, in bytecode, and in `lambda.zip`.
- The login function does not check the password it is given.
- Connect failure calls `sys.exit()` from a bare `except`, which hides the driver error.
- CORS origin is `*`.
- The pipeline can update `qaFunction` from the default pipeline with repository AWS variables. Scope of those variables is **Unknown / Requires Confirmation**.

## Related Silicon Ark directory

`unityNodejsApi` records Lambda name `unityAuth`, the same RDS endpoint and database name, and a Node pipeline of the same deploy pipe. unityAWS does not reference it. Whether `qaFunction` was replaced by `unityAuth` is **Unknown / Requires Confirmation**.
